Compare commits
	
		
			37 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 7577a2dd47 | |||
| 08681756b6 | |||
| 64772d0474 | |||
| 127764556e | |||
| 170f43d806 | |||
| 9dffc41274 | |||
| c63cf442f8 | |||
| a2ba283632 | |||
| 4a1fb1ae18 | |||
| a127b24e62 | |||
| 69d6290376 | |||
| c08a739158 | |||
| 5f5f0e44f0 | |||
| 6e6797eac5 | |||
| cd9406900a | |||
| 6c81f7f6bc | |||
| d56a0235af | |||
| de2ca763c1 | |||
| da52bb5c90 | |||
| 3d4afe7b25 | |||
| f5766d639c | |||
| cdf2a6e76b | |||
| 6d7cfb86f8 | |||
| 1e9d663ffe | |||
| 5b8d7ebf87 | |||
| 11dc6d2640 | |||
| 29a3f73f15 | |||
| 98105642fc | |||
| 0fd5f3b417 | |||
| 43cac4b3bb | |||
| cd68af8e66 | |||
| 113d838876 | |||
| 9e5bc0d3ea | |||
| 6d3bd13f61 | |||
| b5ca475b3f | |||
| a75b1291cb | |||
| 21cd1ee066 | 
							
								
								
									
										6
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										6
									
								
								Makefile
									
									
									
									
									
								
							| @@ -7,5 +7,11 @@ test: | |||||||
| 	which gotestsum || go install gotest.tools/gotestsum@latest | 	which gotestsum || go install gotest.tools/gotestsum@latest | ||||||
| 	gotestsum --format "testname" -- -tags="timetzdata sqlite_fts5 sqlite_foreign_keys" "./..." | 	gotestsum --format "testname" -- -tags="timetzdata sqlite_fts5 sqlite_foreign_keys" "./..." | ||||||
|  |  | ||||||
|  | test-in-docker: | ||||||
|  | 	tag="goext_temp_test_image:$(shell uuidgen | tr -d '-')";        \ | ||||||
|  | 	docker build --tag $$tag . -f .gitea/workflows/Dockerfile_tests; \ | ||||||
|  | 	docker run --rm $$tag;                                           \ | ||||||
|  | 	docker rmi $$tag | ||||||
|  |  | ||||||
| version: | version: | ||||||
| 	_data/version.sh | 	_data/version.sh | ||||||
							
								
								
									
										12
									
								
								TODO.md
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								TODO.md
									
									
									
									
									
								
							| @@ -2,12 +2,6 @@ | |||||||
|  |  | ||||||
|  - cronext |  - cronext | ||||||
|  |  | ||||||
|  - cursortoken |  - rfctime.DateOnly | ||||||
|  |  - rfctime.HMSTimeOnly | ||||||
|  - typed/geenric mongo wrapper |  - rfctime.NanoTimeOnly | ||||||
|  |  | ||||||
|  - error package |  | ||||||
|  |  | ||||||
| - rfctime.DateOnly |  | ||||||
| - rfctime.HMSTimeOnly |  | ||||||
| - rfctime.NanoTimeOnly |  | ||||||
| @@ -31,13 +31,13 @@ type EnumDef struct { | |||||||
| 	Values       []EnumDefVal | 	Values       []EnumDefVal | ||||||
| } | } | ||||||
|  |  | ||||||
| var rexPackage = rext.W(regexp.MustCompile(`^package\s+(?P<name>[A-Za-z0-9_]+)\s*$`)) | var rexEnumPackage = rext.W(regexp.MustCompile(`^package\s+(?P<name>[A-Za-z0-9_]+)\s*$`)) | ||||||
|  |  | ||||||
| var rexEnumDef = rext.W(regexp.MustCompile(`^\s*type\s+(?P<name>[A-Za-z0-9_]+)\s+(?P<type>[A-Za-z0-9_]+)\s*//\s*(@enum:type).*$`)) | var rexEnumDef = rext.W(regexp.MustCompile(`^\s*type\s+(?P<name>[A-Za-z0-9_]+)\s+(?P<type>[A-Za-z0-9_]+)\s*//\s*(@enum:type).*$`)) | ||||||
|  |  | ||||||
| var rexValueDef = rext.W(regexp.MustCompile(`^\s*(?P<name>[A-Za-z0-9_]+)\s+(?P<type>[A-Za-z0-9_]+)\s*=\s*(?P<value>("[A-Za-z0-9_:]+"|[0-9]+))\s*(//(?P<descr>.*))?.*$`)) | var rexEnumValueDef = rext.W(regexp.MustCompile(`^\s*(?P<name>[A-Za-z0-9_]+)\s+(?P<type>[A-Za-z0-9_]+)\s*=\s*(?P<value>("[A-Za-z0-9_:]+"|[0-9]+))\s*(//(?P<descr>.*))?.*$`)) | ||||||
|  |  | ||||||
| var rexChecksumConst = rext.W(regexp.MustCompile(`const ChecksumGenerator = "(?P<cs>[A-Za-z0-9_]*)"`)) | var rexEnumChecksumConst = rext.W(regexp.MustCompile(`const ChecksumEnumGenerator = "(?P<cs>[A-Za-z0-9_]*)"`)) | ||||||
|  |  | ||||||
| func GenerateEnumSpecs(sourceDir string, destFile string) error { | func GenerateEnumSpecs(sourceDir string, destFile string) error { | ||||||
|  |  | ||||||
| @@ -52,13 +52,14 @@ func GenerateEnumSpecs(sourceDir string, destFile string) error { | |||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return err | 			return err | ||||||
| 		} | 		} | ||||||
| 		if m, ok := rexChecksumConst.MatchFirst(string(content)); ok { | 		if m, ok := rexEnumChecksumConst.MatchFirst(string(content)); ok { | ||||||
| 			oldChecksum = m.GroupByName("cs").Value() | 			oldChecksum = m.GroupByName("cs").Value() | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	files = langext.ArrFilter(files, func(v os.DirEntry) bool { return v.Name() != path.Base(destFile) }) | 	files = langext.ArrFilter(files, func(v os.DirEntry) bool { return v.Name() != path.Base(destFile) }) | ||||||
| 	files = langext.ArrFilter(files, func(v os.DirEntry) bool { return strings.HasSuffix(v.Name(), ".go") }) | 	files = langext.ArrFilter(files, func(v os.DirEntry) bool { return strings.HasSuffix(v.Name(), ".go") }) | ||||||
|  | 	files = langext.ArrFilter(files, func(v os.DirEntry) bool { return !strings.HasSuffix(v.Name(), "_gen.go") }) | ||||||
| 	langext.SortBy(files, func(v os.DirEntry) string { return v.Name() }) | 	langext.SortBy(files, func(v os.DirEntry) string { return v.Name() }) | ||||||
|  |  | ||||||
| 	newChecksumStr := goext.GoextVersion | 	newChecksumStr := goext.GoextVersion | ||||||
| @@ -85,7 +86,7 @@ func GenerateEnumSpecs(sourceDir string, destFile string) error { | |||||||
|  |  | ||||||
| 	for _, f := range files { | 	for _, f := range files { | ||||||
| 		fmt.Printf("========= %s =========\n\n", f.Name()) | 		fmt.Printf("========= %s =========\n\n", f.Name()) | ||||||
| 		fileEnums, pn, err := processFile(sourceDir, path.Join(sourceDir, f.Name())) | 		fileEnums, pn, err := processEnumFile(sourceDir, path.Join(sourceDir, f.Name())) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return err | 			return err | ||||||
| 		} | 		} | ||||||
| @@ -103,7 +104,7 @@ func GenerateEnumSpecs(sourceDir string, destFile string) error { | |||||||
| 		return errors.New("no package name found in any file") | 		return errors.New("no package name found in any file") | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	err = os.WriteFile(destFile, []byte(fmtOutput(newChecksum, allEnums, pkgname)), 0o755) | 	err = os.WriteFile(destFile, []byte(fmtEnumOutput(newChecksum, allEnums, pkgname)), 0o755) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| @@ -125,7 +126,7 @@ func GenerateEnumSpecs(sourceDir string, destFile string) error { | |||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
| func processFile(basedir string, fn string) ([]EnumDef, string, error) { | func processEnumFile(basedir string, fn string) ([]EnumDef, string, error) { | ||||||
| 	file, err := os.Open(fn) | 	file, err := os.Open(fn) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, "", err | 		return nil, "", err | ||||||
| @@ -149,7 +150,7 @@ func processFile(basedir string, fn string) ([]EnumDef, string, error) { | |||||||
| 			break | 			break | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		if match, ok := rexPackage.MatchFirst(line); i == 0 && ok { | 		if match, ok := rexEnumPackage.MatchFirst(line); i == 0 && ok { | ||||||
| 			pkgname = match.GroupByName("name").Value() | 			pkgname = match.GroupByName("name").Value() | ||||||
| 			continue | 			continue | ||||||
| 		} | 		} | ||||||
| @@ -172,7 +173,7 @@ func processFile(basedir string, fn string) ([]EnumDef, string, error) { | |||||||
| 			fmt.Printf("Found enum definition { '%s' -> '%s' }\n", def.EnumTypeName, def.Type) | 			fmt.Printf("Found enum definition { '%s' -> '%s' }\n", def.EnumTypeName, def.Type) | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		if match, ok := rexValueDef.MatchFirst(line); ok { | 		if match, ok := rexEnumValueDef.MatchFirst(line); ok { | ||||||
| 			typename := match.GroupByName("type").Value() | 			typename := match.GroupByName("type").Value() | ||||||
| 			def := EnumDefVal{ | 			def := EnumDefVal{ | ||||||
| 				VarName:     match.GroupByName("name").Value(), | 				VarName:     match.GroupByName("name").Value(), | ||||||
| @@ -202,7 +203,7 @@ func processFile(basedir string, fn string) ([]EnumDef, string, error) { | |||||||
| 	return enums, pkgname, nil | 	return enums, pkgname, nil | ||||||
| } | } | ||||||
|  |  | ||||||
| func fmtOutput(cs string, enums []EnumDef, pkgname string) string { | func fmtEnumOutput(cs string, enums []EnumDef, pkgname string) string { | ||||||
| 	str := "// Code generated by enum-generate.go DO NOT EDIT.\n" | 	str := "// Code generated by enum-generate.go DO NOT EDIT.\n" | ||||||
| 	str += "\n" | 	str += "\n" | ||||||
| 	str += "package " + pkgname + "\n" | 	str += "package " + pkgname + "\n" | ||||||
| @@ -212,7 +213,7 @@ func fmtOutput(cs string, enums []EnumDef, pkgname string) string { | |||||||
| 	str += "import \"gogs.mikescher.com/BlackForestBytes/goext/enums\"" + "\n" | 	str += "import \"gogs.mikescher.com/BlackForestBytes/goext/enums\"" + "\n" | ||||||
| 	str += "\n" | 	str += "\n" | ||||||
|  |  | ||||||
| 	str += "const ChecksumGenerator = \"" + cs + "\" // GoExtVersion: " + goext.GoextVersion + "\n" | 	str += "const ChecksumEnumGenerator = \"" + cs + "\" // GoExtVersion: " + goext.GoextVersion + "\n" | ||||||
| 	str += "\n" | 	str += "\n" | ||||||
|  |  | ||||||
| 	for _, enumdef := range enums { | 	for _, enumdef := range enums { | ||||||
|   | |||||||
							
								
								
									
										236
									
								
								bfcodegen/id-generate.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										236
									
								
								bfcodegen/id-generate.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,236 @@ | |||||||
|  | package bfcodegen | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"errors" | ||||||
|  | 	"fmt" | ||||||
|  | 	"gogs.mikescher.com/BlackForestBytes/goext" | ||||||
|  | 	"gogs.mikescher.com/BlackForestBytes/goext/cmdext" | ||||||
|  | 	"gogs.mikescher.com/BlackForestBytes/goext/cryptext" | ||||||
|  | 	"gogs.mikescher.com/BlackForestBytes/goext/langext" | ||||||
|  | 	"gogs.mikescher.com/BlackForestBytes/goext/rext" | ||||||
|  | 	"io" | ||||||
|  | 	"os" | ||||||
|  | 	"path" | ||||||
|  | 	"path/filepath" | ||||||
|  | 	"regexp" | ||||||
|  | 	"strings" | ||||||
|  | 	"time" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | type IDDef struct { | ||||||
|  | 	File         string | ||||||
|  | 	FileRelative string | ||||||
|  | 	Name         string | ||||||
|  | } | ||||||
|  |  | ||||||
|  | var rexIDPackage = rext.W(regexp.MustCompile(`^package\s+(?P<name>[A-Za-z0-9_]+)\s*$`)) | ||||||
|  |  | ||||||
|  | var rexIDDef = rext.W(regexp.MustCompile(`^\s*type\s+(?P<name>[A-Za-z0-9_]+)\s+string\s*//\s*(@id:type).*$`)) | ||||||
|  |  | ||||||
|  | var rexIDChecksumConst = rext.W(regexp.MustCompile(`const ChecksumIDGenerator = "(?P<cs>[A-Za-z0-9_]*)"`)) | ||||||
|  |  | ||||||
|  | func GenerateIDSpecs(sourceDir string, destFile string) error { | ||||||
|  |  | ||||||
|  | 	files, err := os.ReadDir(sourceDir) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	oldChecksum := "N/A" | ||||||
|  | 	if _, err := os.Stat(destFile); !os.IsNotExist(err) { | ||||||
|  | 		content, err := os.ReadFile(destFile) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return err | ||||||
|  | 		} | ||||||
|  | 		if m, ok := rexIDChecksumConst.MatchFirst(string(content)); ok { | ||||||
|  | 			oldChecksum = m.GroupByName("cs").Value() | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	files = langext.ArrFilter(files, func(v os.DirEntry) bool { return v.Name() != path.Base(destFile) }) | ||||||
|  | 	files = langext.ArrFilter(files, func(v os.DirEntry) bool { return strings.HasSuffix(v.Name(), ".go") }) | ||||||
|  | 	files = langext.ArrFilter(files, func(v os.DirEntry) bool { return !strings.HasSuffix(v.Name(), "_gen.go") }) | ||||||
|  | 	langext.SortBy(files, func(v os.DirEntry) string { return v.Name() }) | ||||||
|  |  | ||||||
|  | 	newChecksumStr := goext.GoextVersion | ||||||
|  | 	for _, f := range files { | ||||||
|  | 		content, err := os.ReadFile(path.Join(sourceDir, f.Name())) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return err | ||||||
|  | 		} | ||||||
|  | 		newChecksumStr += "\n" + f.Name() + "\t" + cryptext.BytesSha256(content) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	newChecksum := cryptext.BytesSha256([]byte(newChecksumStr)) | ||||||
|  |  | ||||||
|  | 	if newChecksum != oldChecksum { | ||||||
|  | 		fmt.Printf("[IDGenerate] Checksum has changed ( %s -> %s ), will generate new file\n\n", oldChecksum, newChecksum) | ||||||
|  | 	} else { | ||||||
|  | 		fmt.Printf("[IDGenerate] Checksum unchanged ( %s ), nothing to do\n", oldChecksum) | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	allIDs := make([]IDDef, 0) | ||||||
|  |  | ||||||
|  | 	pkgname := "" | ||||||
|  |  | ||||||
|  | 	for _, f := range files { | ||||||
|  | 		fmt.Printf("========= %s =========\n\n", f.Name()) | ||||||
|  | 		fileIDs, pn, err := processIDFile(sourceDir, path.Join(sourceDir, f.Name())) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return err | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		fmt.Printf("\n") | ||||||
|  |  | ||||||
|  | 		allIDs = append(allIDs, fileIDs...) | ||||||
|  |  | ||||||
|  | 		if pn != "" { | ||||||
|  | 			pkgname = pn | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if pkgname == "" { | ||||||
|  | 		return errors.New("no package name found in any file") | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	err = os.WriteFile(destFile, []byte(fmtIDOutput(newChecksum, allIDs, pkgname)), 0o755) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	res, err := cmdext.RunCommand("go", []string{"fmt", destFile}, langext.Ptr(2*time.Second)) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if res.CommandTimedOut { | ||||||
|  | 		fmt.Println(res.StdCombined) | ||||||
|  | 		return errors.New("go fmt timed out") | ||||||
|  | 	} | ||||||
|  | 	if res.ExitCode != 0 { | ||||||
|  | 		fmt.Println(res.StdCombined) | ||||||
|  | 		return errors.New("go fmt did not succeed") | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func processIDFile(basedir string, fn string) ([]IDDef, string, error) { | ||||||
|  | 	file, err := os.Open(fn) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, "", err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	defer func() { _ = file.Close() }() | ||||||
|  |  | ||||||
|  | 	bin, err := io.ReadAll(file) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, "", err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	lines := strings.Split(string(bin), "\n") | ||||||
|  |  | ||||||
|  | 	ids := make([]IDDef, 0) | ||||||
|  |  | ||||||
|  | 	pkgname := "" | ||||||
|  |  | ||||||
|  | 	for i, line := range lines { | ||||||
|  | 		if i == 0 && strings.HasPrefix(line, "// Code generated by") { | ||||||
|  | 			break | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if match, ok := rexIDPackage.MatchFirst(line); i == 0 && ok { | ||||||
|  | 			pkgname = match.GroupByName("name").Value() | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if match, ok := rexIDDef.MatchFirst(line); ok { | ||||||
|  |  | ||||||
|  | 			rfp, err := filepath.Rel(basedir, fn) | ||||||
|  | 			if err != nil { | ||||||
|  | 				return nil, "", err | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			def := IDDef{ | ||||||
|  | 				File:         fn, | ||||||
|  | 				FileRelative: rfp, | ||||||
|  | 				Name:         match.GroupByName("name").Value(), | ||||||
|  | 			} | ||||||
|  | 			fmt.Printf("Found ID definition { '%s' }\n", def.Name) | ||||||
|  | 			ids = append(ids, def) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return ids, pkgname, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func fmtIDOutput(cs string, ids []IDDef, pkgname string) string { | ||||||
|  | 	str := "// Code generated by id-generate.go DO NOT EDIT.\n" | ||||||
|  | 	str += "\n" | ||||||
|  | 	str += "package " + pkgname + "\n" | ||||||
|  | 	str += "\n" | ||||||
|  |  | ||||||
|  | 	str += "import \"go.mongodb.org/mongo-driver/bson\"" + "\n" | ||||||
|  | 	str += "import \"go.mongodb.org/mongo-driver/bson/bsontype\"" + "\n" | ||||||
|  | 	str += "import \"go.mongodb.org/mongo-driver/bson/primitive\"" + "\n" | ||||||
|  | 	str += "import \"gogs.mikescher.com/BlackForestBytes/goext/exerr\"" + "\n" | ||||||
|  | 	str += "\n" | ||||||
|  |  | ||||||
|  | 	str += "const ChecksumIDGenerator = \"" + cs + "\" // GoExtVersion: " + goext.GoextVersion + "\n" | ||||||
|  | 	str += "\n" | ||||||
|  |  | ||||||
|  | 	anyDef := langext.ArrFirstOrNil(ids, func(def IDDef) bool { return def.Name == "AnyID" || def.Name == "AnyId" }) | ||||||
|  |  | ||||||
|  | 	for _, iddef := range ids { | ||||||
|  |  | ||||||
|  | 		str += "// ================================ " + iddef.Name + " (" + iddef.FileRelative + ") ================================" + "\n" | ||||||
|  | 		str += "" + "\n" | ||||||
|  |  | ||||||
|  | 		str += "func (i " + iddef.Name + ") MarshalBSONValue() (bsontype.Type, []byte, error) {" + "\n" | ||||||
|  | 		str += "	if objId, err := primitive.ObjectIDFromHex(string(i)); err == nil {" + "\n" | ||||||
|  | 		str += "		return bson.MarshalValue(objId)" + "\n" | ||||||
|  | 		str += "	} else {" + "\n" | ||||||
|  | 		str += "		return 0, nil, exerr.New(exerr.TypeMarshalEntityID, \"Failed to marshal " + iddef.Name + "(\"+i.String()+\") to ObjectId\").Str(\"value\", string(i)).Type(\"type\", i).Build()" + "\n" | ||||||
|  | 		str += "	}" + "\n" | ||||||
|  | 		str += "}" + "\n" | ||||||
|  |  | ||||||
|  | 		str += "" + "\n" | ||||||
|  |  | ||||||
|  | 		str += "func (i " + iddef.Name + ") String() string {" + "\n" | ||||||
|  | 		str += "	return string(i)" + "\n" | ||||||
|  | 		str += "}" + "\n" | ||||||
|  |  | ||||||
|  | 		str += "" + "\n" | ||||||
|  |  | ||||||
|  | 		str += "func (i " + iddef.Name + ") ObjID() (primitive.ObjectID, error) {" + "\n" | ||||||
|  | 		str += "	return primitive.ObjectIDFromHex(string(i))" + "\n" | ||||||
|  | 		str += "}" + "\n" | ||||||
|  |  | ||||||
|  | 		str += "" + "\n" | ||||||
|  |  | ||||||
|  | 		str += "func (i " + iddef.Name + ") Valid() bool {" + "\n" | ||||||
|  | 		str += "	_, err := primitive.ObjectIDFromHex(string(i))" + "\n" | ||||||
|  | 		str += "	return err == nil" + "\n" | ||||||
|  | 		str += "}" + "\n" | ||||||
|  |  | ||||||
|  | 		str += "" + "\n" | ||||||
|  |  | ||||||
|  | 		if anyDef != nil { | ||||||
|  | 			str += "func (i " + iddef.Name + ") AsAny() " + anyDef.Name + " {" + "\n" | ||||||
|  | 			str += "	return " + anyDef.Name + "(i)" + "\n" | ||||||
|  | 			str += "}" + "\n" | ||||||
|  |  | ||||||
|  | 			str += "" + "\n" | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		str += "func New" + iddef.Name + "() " + iddef.Name + " {" + "\n" | ||||||
|  | 		str += "	return " + iddef.Name + "(primitive.NewObjectID().Hex())" + "\n" | ||||||
|  | 		str += "}" + "\n" | ||||||
|  |  | ||||||
|  | 		str += "" + "\n" | ||||||
|  |  | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return str | ||||||
|  | } | ||||||
| @@ -133,9 +133,6 @@ func run(opt CommandRunner) (CommandResult, error) { | |||||||
|  |  | ||||||
| 	case <-stderrFailChan: | 	case <-stderrFailChan: | ||||||
| 		_ = cmd.Process.Kill() | 		_ = cmd.Process.Kill() | ||||||
| 		for _, lstr := range opt.listener { |  | ||||||
| 			lstr.Timeout() |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		if fallback, ok := syncext.ReadChannelWithTimeout(outputChan, 32*time.Millisecond); ok { | 		if fallback, ok := syncext.ReadChannelWithTimeout(outputChan, 32*time.Millisecond); ok { | ||||||
| 			// most of the time the cmd.Process.Kill() should also have finished the pipereader | 			// most of the time the cmd.Process.Kill() should also have finished the pipereader | ||||||
| @@ -160,7 +157,8 @@ func run(opt CommandRunner) (CommandResult, error) { | |||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 	case outobj := <-outputChan: | 	case outobj := <-outputChan: | ||||||
| 		if exiterr, ok := outobj.err.(*exec.ExitError); ok { | 		var exiterr *exec.ExitError | ||||||
|  | 		if errors.As(outobj.err, &exiterr) { | ||||||
| 			excode := exiterr.ExitCode() | 			excode := exiterr.ExitCode() | ||||||
| 			for _, lstr := range opt.listener { | 			for _, lstr := range opt.listener { | ||||||
| 				lstr.Finished(excode) | 				lstr.Finished(excode) | ||||||
|   | |||||||
| @@ -32,8 +32,8 @@ func (pr *pipeReader) Read(listener []CommandListener) (string, string, string, | |||||||
| 	stdout := "" | 	stdout := "" | ||||||
| 	go func() { | 	go func() { | ||||||
| 		buf := make([]byte, 128) | 		buf := make([]byte, 128) | ||||||
| 		for true { | 		for { | ||||||
| 			n, out := pr.stdout.Read(buf) | 			n, err := pr.stdout.Read(buf) | ||||||
| 			if n > 0 { | 			if n > 0 { | ||||||
| 				txt := string(buf[:n]) | 				txt := string(buf[:n]) | ||||||
| 				stdout += txt | 				stdout += txt | ||||||
| @@ -42,11 +42,11 @@ func (pr *pipeReader) Read(listener []CommandListener) (string, string, string, | |||||||
| 					lstr.ReadRawStdout(buf[:n]) | 					lstr.ReadRawStdout(buf[:n]) | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 			if out == io.EOF { | 			if err == io.EOF { | ||||||
| 				break | 				break | ||||||
| 			} | 			} | ||||||
| 			if out != nil { | 			if err != nil { | ||||||
| 				errch <- out | 				errch <- err | ||||||
| 				break | 				break | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| @@ -61,7 +61,7 @@ func (pr *pipeReader) Read(listener []CommandListener) (string, string, string, | |||||||
| 	stderr := "" | 	stderr := "" | ||||||
| 	go func() { | 	go func() { | ||||||
| 		buf := make([]byte, 128) | 		buf := make([]byte, 128) | ||||||
| 		for true { | 		for { | ||||||
| 			n, err := pr.stderr.Read(buf) | 			n, err := pr.stderr.Read(buf) | ||||||
|  |  | ||||||
| 			if n > 0 { | 			if n > 0 { | ||||||
|   | |||||||
							
								
								
									
										170
									
								
								dataext/tuple.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										170
									
								
								dataext/tuple.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,170 @@ | |||||||
|  | package dataext | ||||||
|  |  | ||||||
|  | type ValueGroup interface { | ||||||
|  | 	TupleLength() int | ||||||
|  | 	TupleValues() []any | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ---------------------------------------------------------------------------- | ||||||
|  |  | ||||||
|  | type Single[T1 any] struct { | ||||||
|  | 	V1 T1 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (s Single[T1]) TupleLength() int { | ||||||
|  | 	return 1 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (s Single[T1]) TupleValues() []any { | ||||||
|  | 	return []any{s.V1} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ---------------------------------------------------------------------------- | ||||||
|  |  | ||||||
|  | type Tuple[T1 any, T2 any] struct { | ||||||
|  | 	V1 T1 | ||||||
|  | 	V2 T2 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (t Tuple[T1, T2]) TupleLength() int { | ||||||
|  | 	return 2 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (t Tuple[T1, T2]) TupleValues() []any { | ||||||
|  | 	return []any{t.V1, t.V2} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ---------------------------------------------------------------------------- | ||||||
|  |  | ||||||
|  | type Triple[T1 any, T2 any, T3 any] struct { | ||||||
|  | 	V1 T1 | ||||||
|  | 	V2 T2 | ||||||
|  | 	V3 T3 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (t Triple[T1, T2, T3]) TupleLength() int { | ||||||
|  | 	return 3 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (t Triple[T1, T2, T3]) TupleValues() []any { | ||||||
|  | 	return []any{t.V1, t.V2, t.V3} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ---------------------------------------------------------------------------- | ||||||
|  |  | ||||||
|  | type Quadruple[T1 any, T2 any, T3 any, T4 any] struct { | ||||||
|  | 	V1 T1 | ||||||
|  | 	V2 T2 | ||||||
|  | 	V3 T3 | ||||||
|  | 	V4 T4 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (t Quadruple[T1, T2, T3, T4]) TupleLength() int { | ||||||
|  | 	return 4 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (t Quadruple[T1, T2, T3, T4]) TupleValues() []any { | ||||||
|  | 	return []any{t.V1, t.V2, t.V3, t.V4} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ---------------------------------------------------------------------------- | ||||||
|  |  | ||||||
|  | type Quintuple[T1 any, T2 any, T3 any, T4 any, T5 any] struct { | ||||||
|  | 	V1 T1 | ||||||
|  | 	V2 T2 | ||||||
|  | 	V3 T3 | ||||||
|  | 	V4 T4 | ||||||
|  | 	V5 T5 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (t Quintuple[T1, T2, T3, T4, T5]) TupleLength() int { | ||||||
|  | 	return 5 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (t Quintuple[T1, T2, T3, T4, T5]) TupleValues() []any { | ||||||
|  | 	return []any{t.V1, t.V2, t.V3, t.V4, t.V5} | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ---------------------------------------------------------------------------- | ||||||
|  |  | ||||||
|  | type Sextuple[T1 any, T2 any, T3 any, T4 any, T5 any, T6 any] struct { | ||||||
|  | 	V1 T1 | ||||||
|  | 	V2 T2 | ||||||
|  | 	V3 T3 | ||||||
|  | 	V4 T4 | ||||||
|  | 	V5 T5 | ||||||
|  | 	V6 T6 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (t Sextuple[T1, T2, T3, T4, T5, T6]) TupleLength() int { | ||||||
|  | 	return 6 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (t Sextuple[T1, T2, T3, T4, T5, T6]) TupleValues() []any { | ||||||
|  | 	return []any{t.V1, t.V2, t.V3, t.V4, t.V5, t.V6} | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ---------------------------------------------------------------------------- | ||||||
|  |  | ||||||
|  | type Septuple[T1 any, T2 any, T3 any, T4 any, T5 any, T6 any, T7 any] struct { | ||||||
|  | 	V1 T1 | ||||||
|  | 	V2 T2 | ||||||
|  | 	V3 T3 | ||||||
|  | 	V4 T4 | ||||||
|  | 	V5 T5 | ||||||
|  | 	V6 T6 | ||||||
|  | 	V7 T7 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (t Septuple[T1, T2, T3, T4, T5, T6, T7]) TupleLength() int { | ||||||
|  | 	return 7 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (t Septuple[T1, T2, T3, T4, T5, T6, T7]) TupleValues() []any { | ||||||
|  | 	return []any{t.V1, t.V2, t.V3, t.V4, t.V5, t.V6, t.V7} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ---------------------------------------------------------------------------- | ||||||
|  |  | ||||||
|  | type Octuple[T1 any, T2 any, T3 any, T4 any, T5 any, T6 any, T7 any, T8 any] struct { | ||||||
|  | 	V1 T1 | ||||||
|  | 	V2 T2 | ||||||
|  | 	V3 T3 | ||||||
|  | 	V4 T4 | ||||||
|  | 	V5 T5 | ||||||
|  | 	V6 T6 | ||||||
|  | 	V7 T7 | ||||||
|  | 	V8 T8 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (t Octuple[T1, T2, T3, T4, T5, T6, T7, T8]) TupleLength() int { | ||||||
|  | 	return 8 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (t Octuple[T1, T2, T3, T4, T5, T6, T7, T8]) TupleValues() []any { | ||||||
|  | 	return []any{t.V1, t.V2, t.V3, t.V4, t.V5, t.V6, t.V7, t.V8} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ---------------------------------------------------------------------------- | ||||||
|  |  | ||||||
|  | type Nonuple[T1 any, T2 any, T3 any, T4 any, T5 any, T6 any, T7 any, T8 any, T9 any] struct { | ||||||
|  | 	V1 T1 | ||||||
|  | 	V2 T2 | ||||||
|  | 	V3 T3 | ||||||
|  | 	V4 T4 | ||||||
|  | 	V5 T5 | ||||||
|  | 	V6 T6 | ||||||
|  | 	V7 T7 | ||||||
|  | 	V8 T8 | ||||||
|  | 	V9 T9 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (t Nonuple[T1, T2, T3, T4, T5, T6, T7, T8, T9]) TupleLength() int { | ||||||
|  | 	return 9 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (t Nonuple[T1, T2, T3, T4, T5, T6, T7, T8, T9]) TupleValues() []any { | ||||||
|  | 	return []any{t.V1, t.V2, t.V3, t.V4, t.V5, t.V6, t.V7, t.V8, t.V9} | ||||||
|  | } | ||||||
| @@ -55,6 +55,8 @@ var ( | |||||||
| 	TypeBindFailFormData = NewType("BINDFAIL_FORMDATA", langext.Ptr(400)) | 	TypeBindFailFormData = NewType("BINDFAIL_FORMDATA", langext.Ptr(400)) | ||||||
| 	TypeBindFailHeader   = NewType("BINDFAIL_HEADER", langext.Ptr(400)) | 	TypeBindFailHeader   = NewType("BINDFAIL_HEADER", langext.Ptr(400)) | ||||||
|  |  | ||||||
|  | 	TypeMarshalEntityID = NewType("MARSHAL_ENTITY_ID", langext.Ptr(400)) | ||||||
|  |  | ||||||
| 	TypeUnauthorized = NewType("UNAUTHORIZED", langext.Ptr(401)) | 	TypeUnauthorized = NewType("UNAUTHORIZED", langext.Ptr(401)) | ||||||
| 	TypeAuthFailed   = NewType("AUTH_FAILED", langext.Ptr(401)) | 	TypeAuthFailed   = NewType("AUTH_FAILED", langext.Ptr(401)) | ||||||
|  |  | ||||||
|   | |||||||
| @@ -164,7 +164,7 @@ func (ee *ExErr) FormatLog(lvl LogPrintLevel) string { | |||||||
| } | } | ||||||
|  |  | ||||||
| func (ee *ExErr) ShortLog(evt *zerolog.Event) { | func (ee *ExErr) ShortLog(evt *zerolog.Event) { | ||||||
| 	ee.Meta.Apply(evt).Msg(ee.FormatLog(LogPrintShort)) | 	ee.Meta.Apply(evt, langext.Ptr(240)).Msg(ee.FormatLog(LogPrintShort)) | ||||||
| } | } | ||||||
|  |  | ||||||
| // RecursiveMessage returns the message to show | // RecursiveMessage returns the message to show | ||||||
|   | |||||||
| @@ -217,23 +217,35 @@ func (v MetaValue) ShortString(lim int) string { | |||||||
| 	return "(err)" | 	return "(err)" | ||||||
| } | } | ||||||
|  |  | ||||||
| func (v MetaValue) Apply(key string, evt *zerolog.Event) *zerolog.Event { | func (v MetaValue) Apply(key string, evt *zerolog.Event, limitLen *int) *zerolog.Event { | ||||||
| 	switch v.DataType { | 	switch v.DataType { | ||||||
| 	case MDTString: | 	case MDTString: | ||||||
|  | 		if limitLen == nil { | ||||||
| 			return evt.Str(key, v.Value.(string)) | 			return evt.Str(key, v.Value.(string)) | ||||||
|  | 		} else { | ||||||
|  | 			evt.Str(key, langext.StrLimit(v.Value.(string), *limitLen, "...")) | ||||||
|  | 		} | ||||||
| 	case MDTID: | 	case MDTID: | ||||||
| 		return evt.Str(key, v.Value.(IDWrap).Value) | 		return evt.Str(key, v.Value.(IDWrap).Value) | ||||||
| 	case MDTAny: | 	case MDTAny: | ||||||
| 		if v.Value.(AnyWrap).IsError { | 		if v.Value.(AnyWrap).IsError { | ||||||
| 			return evt.Str(key, "(err)") | 			return evt.Str(key, "(err)") | ||||||
| 		} else { | 		} else { | ||||||
|  | 			if limitLen == nil { | ||||||
| 				return evt.Str(key, v.Value.(AnyWrap).Json) | 				return evt.Str(key, v.Value.(AnyWrap).Json) | ||||||
|  | 			} else { | ||||||
|  | 				evt.Str(key, langext.StrLimit(v.Value.(AnyWrap).Json, *limitLen, "...")) | ||||||
|  | 			} | ||||||
| 		} | 		} | ||||||
| 	case MDTStringPtr: | 	case MDTStringPtr: | ||||||
| 		if langext.IsNil(v.Value) { | 		if langext.IsNil(v.Value) { | ||||||
| 			return evt.Str(key, "<<null>>") | 			return evt.Str(key, "<<null>>") | ||||||
| 		} | 		} | ||||||
|  | 		if limitLen == nil { | ||||||
| 			return evt.Str(key, langext.CoalesceString(v.Value.(*string), "<<null>>")) | 			return evt.Str(key, langext.CoalesceString(v.Value.(*string), "<<null>>")) | ||||||
|  | 		} else { | ||||||
|  | 			evt.Str(key, langext.StrLimit(langext.CoalesceString(v.Value.(*string), "<<null>>"), *limitLen, "...")) | ||||||
|  | 		} | ||||||
| 	case MDTInt: | 	case MDTInt: | ||||||
| 		return evt.Int(key, v.Value.(int)) | 		return evt.Int(key, v.Value.(int)) | ||||||
| 	case MDTInt8: | 	case MDTInt8: | ||||||
| @@ -612,7 +624,18 @@ func (v MetaValue) rawValueForJson() any { | |||||||
| 		if v.Value.(AnyWrap).IsNil { | 		if v.Value.(AnyWrap).IsNil { | ||||||
| 			return nil | 			return nil | ||||||
| 		} | 		} | ||||||
| 		return v.Value.(AnyWrap).Serialize() | 		if v.Value.(AnyWrap).IsError { | ||||||
|  | 			return bson.M{"@error": true} | ||||||
|  | 		} | ||||||
|  | 		jsonobj := primitive.M{} | ||||||
|  | 		jsonarr := primitive.A{} | ||||||
|  | 		if err := json.Unmarshal([]byte(v.Value.(AnyWrap).Json), &jsonobj); err == nil { | ||||||
|  | 			return jsonobj | ||||||
|  | 		} else if err := json.Unmarshal([]byte(v.Value.(AnyWrap).Json), &jsonarr); err == nil { | ||||||
|  | 			return jsonarr | ||||||
|  | 		} else { | ||||||
|  | 			return bson.M{"type": v.Value.(AnyWrap).Type, "data": v.Value.(AnyWrap).Json} | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
| 	if v.DataType == MDTID { | 	if v.DataType == MDTID { | ||||||
| 		if v.Value.(IDWrap).IsNil { | 		if v.Value.(IDWrap).IsNil { | ||||||
| @@ -691,9 +714,9 @@ func (mm MetaMap) Any() bool { | |||||||
| 	return len(mm) > 0 | 	return len(mm) > 0 | ||||||
| } | } | ||||||
|  |  | ||||||
| func (mm MetaMap) Apply(evt *zerolog.Event) *zerolog.Event { | func (mm MetaMap) Apply(evt *zerolog.Event, limitLen *int) *zerolog.Event { | ||||||
| 	for key, val := range mm { | 	for key, val := range mm { | ||||||
| 		evt = val.Apply(key, evt) | 		evt = val.Apply(key, evt, limitLen) | ||||||
| 	} | 	} | ||||||
| 	return evt | 	return evt | ||||||
| } | } | ||||||
|   | |||||||
| @@ -116,7 +116,7 @@ func (pctx PreContext) Start() (*AppContext, *gin.Context, *HTTPResponse) { | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if pctx.header != nil { | 	if pctx.header != nil { | ||||||
| 		if err := pctx.ginCtx.ShouldBindHeader(pctx.query); err != nil { | 		if err := pctx.ginCtx.ShouldBindHeader(pctx.header); err != nil { | ||||||
| 			err = exerr.Wrap(err, "Failed to read header"). | 			err = exerr.Wrap(err, "Failed to read header"). | ||||||
| 				WithType(exerr.TypeBindFailHeader). | 				WithType(exerr.TypeBindFailHeader). | ||||||
| 				Str("struct_type", fmt.Sprintf("%T", pctx.query)). | 				Str("struct_type", fmt.Sprintf("%T", pctx.query)). | ||||||
|   | |||||||
							
								
								
									
										22
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										22
									
								
								go.mod
									
									
									
									
									
								
							| @@ -6,26 +6,26 @@ require ( | |||||||
| 	github.com/gin-gonic/gin v1.9.1 | 	github.com/gin-gonic/gin v1.9.1 | ||||||
| 	github.com/jmoiron/sqlx v1.3.5 | 	github.com/jmoiron/sqlx v1.3.5 | ||||||
| 	github.com/rs/xid v1.5.0 | 	github.com/rs/xid v1.5.0 | ||||||
| 	github.com/rs/zerolog v1.30.0 | 	github.com/rs/zerolog v1.31.0 | ||||||
| 	go.mongodb.org/mongo-driver v1.12.1 | 	go.mongodb.org/mongo-driver v1.12.1 | ||||||
| 	golang.org/x/crypto v0.12.0 | 	golang.org/x/crypto v0.13.0 | ||||||
| 	golang.org/x/sys v0.11.0 | 	golang.org/x/sys v0.12.0 | ||||||
| 	golang.org/x/term v0.11.0 | 	golang.org/x/term v0.12.0 | ||||||
| ) | ) | ||||||
|  |  | ||||||
| require ( | require ( | ||||||
| 	github.com/bytedance/sonic v1.10.0 // indirect | 	github.com/bytedance/sonic v1.10.1 // indirect | ||||||
| 	github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect | 	github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect | ||||||
| 	github.com/chenzhuoyu/iasm v0.9.0 // indirect | 	github.com/chenzhuoyu/iasm v0.9.0 // indirect | ||||||
| 	github.com/gabriel-vasile/mimetype v1.4.2 // indirect | 	github.com/gabriel-vasile/mimetype v1.4.2 // indirect | ||||||
| 	github.com/gin-contrib/sse v0.1.0 // indirect | 	github.com/gin-contrib/sse v0.1.0 // indirect | ||||||
| 	github.com/go-playground/locales v0.14.1 // indirect | 	github.com/go-playground/locales v0.14.1 // indirect | ||||||
| 	github.com/go-playground/universal-translator v0.18.1 // indirect | 	github.com/go-playground/universal-translator v0.18.1 // indirect | ||||||
| 	github.com/go-playground/validator/v10 v10.15.1 // indirect | 	github.com/go-playground/validator/v10 v10.15.4 // indirect | ||||||
| 	github.com/goccy/go-json v0.10.2 // indirect | 	github.com/goccy/go-json v0.10.2 // indirect | ||||||
| 	github.com/golang/snappy v0.0.4 // indirect | 	github.com/golang/snappy v0.0.4 // indirect | ||||||
| 	github.com/json-iterator/go v1.1.12 // indirect | 	github.com/json-iterator/go v1.1.12 // indirect | ||||||
| 	github.com/klauspost/compress v1.16.7 // indirect | 	github.com/klauspost/compress v1.17.0 // indirect | ||||||
| 	github.com/klauspost/cpuid/v2 v2.2.5 // indirect | 	github.com/klauspost/cpuid/v2 v2.2.5 // indirect | ||||||
| 	github.com/leodido/go-urn v1.2.4 // indirect | 	github.com/leodido/go-urn v1.2.4 // indirect | ||||||
| 	github.com/mattn/go-colorable v0.1.13 // indirect | 	github.com/mattn/go-colorable v0.1.13 // indirect | ||||||
| @@ -33,7 +33,7 @@ require ( | |||||||
| 	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect | 	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect | ||||||
| 	github.com/modern-go/reflect2 v1.0.2 // indirect | 	github.com/modern-go/reflect2 v1.0.2 // indirect | ||||||
| 	github.com/montanaflynn/stats v0.7.1 // indirect | 	github.com/montanaflynn/stats v0.7.1 // indirect | ||||||
| 	github.com/pelletier/go-toml/v2 v2.0.9 // indirect | 	github.com/pelletier/go-toml/v2 v2.1.0 // indirect | ||||||
| 	github.com/pkg/errors v0.9.1 // indirect | 	github.com/pkg/errors v0.9.1 // indirect | ||||||
| 	github.com/twitchyliquid64/golang-asm v0.15.1 // indirect | 	github.com/twitchyliquid64/golang-asm v0.15.1 // indirect | ||||||
| 	github.com/ugorji/go/codec v1.2.11 // indirect | 	github.com/ugorji/go/codec v1.2.11 // indirect | ||||||
| @@ -41,10 +41,10 @@ require ( | |||||||
| 	github.com/xdg-go/scram v1.1.2 // indirect | 	github.com/xdg-go/scram v1.1.2 // indirect | ||||||
| 	github.com/xdg-go/stringprep v1.0.4 // indirect | 	github.com/xdg-go/stringprep v1.0.4 // indirect | ||||||
| 	github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a // indirect | 	github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a // indirect | ||||||
| 	golang.org/x/arch v0.4.0 // indirect | 	golang.org/x/arch v0.5.0 // indirect | ||||||
| 	golang.org/x/net v0.14.0 // indirect | 	golang.org/x/net v0.15.0 // indirect | ||||||
| 	golang.org/x/sync v0.3.0 // indirect | 	golang.org/x/sync v0.3.0 // indirect | ||||||
| 	golang.org/x/text v0.12.0 // indirect | 	golang.org/x/text v0.13.0 // indirect | ||||||
| 	google.golang.org/protobuf v1.31.0 // indirect | 	google.golang.org/protobuf v1.31.0 // indirect | ||||||
| 	gopkg.in/yaml.v3 v3.0.1 // indirect | 	gopkg.in/yaml.v3 v3.0.1 // indirect | ||||||
| ) | ) | ||||||
|   | |||||||
							
								
								
									
										24
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										24
									
								
								go.sum
									
									
									
									
									
								
							| @@ -6,6 +6,8 @@ github.com/bytedance/sonic v1.10.0-rc3 h1:uNSnscRapXTwUgTyOF0GVljYD08p9X/Lbr9Mwe | |||||||
| github.com/bytedance/sonic v1.10.0-rc3/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4= | github.com/bytedance/sonic v1.10.0-rc3/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4= | ||||||
| github.com/bytedance/sonic v1.10.0 h1:qtNZduETEIWJVIyDl01BeNxur2rW9OwTQ/yBqFRkKEk= | github.com/bytedance/sonic v1.10.0 h1:qtNZduETEIWJVIyDl01BeNxur2rW9OwTQ/yBqFRkKEk= | ||||||
| github.com/bytedance/sonic v1.10.0/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4= | github.com/bytedance/sonic v1.10.0/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4= | ||||||
|  | github.com/bytedance/sonic v1.10.1 h1:7a1wuFXL1cMy7a3f7/VFcEtriuXQnUBhtoVfOZiaysc= | ||||||
|  | github.com/bytedance/sonic v1.10.1/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4= | ||||||
| github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= | github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= | ||||||
| github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= | github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= | ||||||
| github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d h1:77cEq6EriyTZ0g/qfRdp61a3Uu/AWrgIq2s0ClJV1g0= | github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d h1:77cEq6EriyTZ0g/qfRdp61a3Uu/AWrgIq2s0ClJV1g0= | ||||||
| @@ -32,6 +34,10 @@ github.com/go-playground/validator/v10 v10.15.0 h1:nDU5XeOKtB3GEa+uB7GNYwhVKsgjA | |||||||
| github.com/go-playground/validator/v10 v10.15.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= | github.com/go-playground/validator/v10 v10.15.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= | ||||||
| github.com/go-playground/validator/v10 v10.15.1 h1:BSe8uhN+xQ4r5guV/ywQI4gO59C2raYcGffYWZEjZzM= | github.com/go-playground/validator/v10 v10.15.1 h1:BSe8uhN+xQ4r5guV/ywQI4gO59C2raYcGffYWZEjZzM= | ||||||
| github.com/go-playground/validator/v10 v10.15.1/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= | github.com/go-playground/validator/v10 v10.15.1/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= | ||||||
|  | github.com/go-playground/validator/v10 v10.15.3 h1:S+sSpunYjNPDuXkWbK+x+bA7iXiW296KG4dL3X7xUZo= | ||||||
|  | github.com/go-playground/validator/v10 v10.15.3/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= | ||||||
|  | github.com/go-playground/validator/v10 v10.15.4 h1:zMXza4EpOdooxPel5xDqXEdXG5r+WggpvnAKMsalBjs= | ||||||
|  | github.com/go-playground/validator/v10 v10.15.4/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= | ||||||
| github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= | github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= | ||||||
| github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= | github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= | ||||||
| github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= | github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= | ||||||
| @@ -52,6 +58,8 @@ github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQ | |||||||
| github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= | github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= | ||||||
| github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I= | github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I= | ||||||
| github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= | github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= | ||||||
|  | github.com/klauspost/compress v1.17.0 h1:Rnbp4K9EjcDuVuHtd0dgA4qNuv9yKDYKK1ulpJwgrqM= | ||||||
|  | github.com/klauspost/compress v1.17.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= | ||||||
| github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= | github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= | ||||||
| github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg= | github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg= | ||||||
| github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= | github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= | ||||||
| @@ -83,6 +91,8 @@ github.com/montanaflynn/stats v0.7.1 h1:etflOAAHORrCC44V+aR6Ftzort912ZU+YLiSTuV8 | |||||||
| github.com/montanaflynn/stats v0.7.1/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow= | github.com/montanaflynn/stats v0.7.1/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow= | ||||||
| github.com/pelletier/go-toml/v2 v2.0.9 h1:uH2qQXheeefCCkuBBSLi7jCiSmj3VRh2+Goq2N7Xxu0= | github.com/pelletier/go-toml/v2 v2.0.9 h1:uH2qQXheeefCCkuBBSLi7jCiSmj3VRh2+Goq2N7Xxu0= | ||||||
| github.com/pelletier/go-toml/v2 v2.0.9/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= | github.com/pelletier/go-toml/v2 v2.0.9/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= | ||||||
|  | github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4= | ||||||
|  | github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= | ||||||
| github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= | ||||||
| github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= | ||||||
| github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | ||||||
| @@ -95,6 +105,8 @@ github.com/rs/zerolog v1.29.1 h1:cO+d60CHkknCbvzEWxP0S9K6KqyTjrCNUy1LdQLCGPc= | |||||||
| github.com/rs/zerolog v1.29.1/go.mod h1:Le6ESbR7hc+DP6Lt1THiV8CQSdkkNrd3R0XbEgp3ZBU= | github.com/rs/zerolog v1.29.1/go.mod h1:Le6ESbR7hc+DP6Lt1THiV8CQSdkkNrd3R0XbEgp3ZBU= | ||||||
| github.com/rs/zerolog v1.30.0 h1:SymVODrcRsaRaSInD9yQtKbtWqwsfoPcRff/oRXLj4c= | github.com/rs/zerolog v1.30.0 h1:SymVODrcRsaRaSInD9yQtKbtWqwsfoPcRff/oRXLj4c= | ||||||
| github.com/rs/zerolog v1.30.0/go.mod h1:/tk+P47gFdPXq4QYjvCmT5/Gsug2nagsFWBWhAiSi1w= | github.com/rs/zerolog v1.30.0/go.mod h1:/tk+P47gFdPXq4QYjvCmT5/Gsug2nagsFWBWhAiSi1w= | ||||||
|  | github.com/rs/zerolog v1.31.0 h1:FcTR3NnLWW+NnTwwhFWiJSZr4ECLpqCm6QsEnyvbV4A= | ||||||
|  | github.com/rs/zerolog v1.31.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= | ||||||
| github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= | ||||||
| github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= | github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= | ||||||
| github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= | github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= | ||||||
| @@ -135,6 +147,8 @@ go.mongodb.org/mongo-driver v1.12.1/go.mod h1:/rGBTebI3XYboVmgz+Wv3Bcbl3aD0QF9zl | |||||||
| golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= | golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= | ||||||
| golang.org/x/arch v0.4.0 h1:A8WCeEWhLwPBKNbFi5Wv5UTCBx5zzubnXDlMOFAzFMc= | golang.org/x/arch v0.4.0 h1:A8WCeEWhLwPBKNbFi5Wv5UTCBx5zzubnXDlMOFAzFMc= | ||||||
| golang.org/x/arch v0.4.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= | golang.org/x/arch v0.4.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= | ||||||
|  | golang.org/x/arch v0.5.0 h1:jpGode6huXQxcskEIpOCvrU+tzo81b6+oFLUYXWtH/Y= | ||||||
|  | golang.org/x/arch v0.5.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= | ||||||
| golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= | ||||||
| golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= | golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= | ||||||
| golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= | golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= | ||||||
| @@ -145,6 +159,8 @@ golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA= | |||||||
| golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= | golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= | ||||||
| golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk= | golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk= | ||||||
| golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= | golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= | ||||||
|  | golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck= | ||||||
|  | golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= | ||||||
| golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= | golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= | ||||||
| golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= | ||||||
| golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= | ||||||
| @@ -157,6 +173,8 @@ golang.org/x/net v0.13.0 h1:Nvo8UFsZ8X3BhAC9699Z1j7XQ3rsZnUUm7jfBEk1ueY= | |||||||
| golang.org/x/net v0.13.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= | golang.org/x/net v0.13.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= | ||||||
| golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14= | golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14= | ||||||
| golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= | golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= | ||||||
|  | golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8= | ||||||
|  | golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= | ||||||
| golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||||||
| golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= | golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= | ||||||
| golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||||||
| @@ -184,6 +202,8 @@ golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA= | |||||||
| golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||||||
| golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= | golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= | ||||||
| golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||||||
|  | golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= | ||||||
|  | golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||||||
| golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= | ||||||
| golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= | golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= | ||||||
| golang.org/x/term v0.1.0 h1:g6Z6vPFA9dYBAF7DWcH6sCcOntplXsDKcliusYijMlw= | golang.org/x/term v0.1.0 h1:g6Z6vPFA9dYBAF7DWcH6sCcOntplXsDKcliusYijMlw= | ||||||
| @@ -194,6 +214,8 @@ golang.org/x/term v0.10.0 h1:3R7pNqamzBraeqj/Tj8qt1aQ2HpmlC+Cx/qL/7hn4/c= | |||||||
| golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o= | golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o= | ||||||
| golang.org/x/term v0.11.0 h1:F9tnn/DA/Im8nCwm+fX+1/eBwi4qFjRT++MhtVC4ZX0= | golang.org/x/term v0.11.0 h1:F9tnn/DA/Im8nCwm+fX+1/eBwi4qFjRT++MhtVC4ZX0= | ||||||
| golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= | golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= | ||||||
|  | golang.org/x/term v0.12.0 h1:/ZfYdc3zq+q02Rv9vGqTeSItdzZTSNDmfTi0mBAuidU= | ||||||
|  | golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= | ||||||
| golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= | ||||||
| golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= | ||||||
| golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= | ||||||
| @@ -206,6 +228,8 @@ golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4= | |||||||
| golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= | golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= | ||||||
| golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc= | golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc= | ||||||
| golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= | golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= | ||||||
|  | golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= | ||||||
|  | golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= | ||||||
| golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= | ||||||
| golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= | ||||||
| golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= | golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= | ||||||
|   | |||||||
| @@ -1,5 +1,5 @@ | |||||||
| package goext | package goext | ||||||
|  |  | ||||||
| const GoextVersion = "0.0.248" | const GoextVersion = "0.0.274" | ||||||
|  |  | ||||||
| const GoextVersionTimestamp = "2023-08-21T15:08:35+0200" | const GoextVersionTimestamp = "2023-09-27T16:18:21+0200" | ||||||
|   | |||||||
| @@ -1,7 +1,10 @@ | |||||||
| package langext | package langext | ||||||
|  |  | ||||||
|  | import "runtime/debug" | ||||||
|  |  | ||||||
| type PanicWrappedErr struct { | type PanicWrappedErr struct { | ||||||
| 	panic any | 	panic any | ||||||
|  | 	Stack string | ||||||
| } | } | ||||||
|  |  | ||||||
| func (p PanicWrappedErr) Error() string { | func (p PanicWrappedErr) Error() string { | ||||||
| @@ -15,7 +18,7 @@ func (p PanicWrappedErr) ReoveredObj() any { | |||||||
| func RunPanicSafe(fn func()) (err error) { | func RunPanicSafe(fn func()) (err error) { | ||||||
| 	defer func() { | 	defer func() { | ||||||
| 		if rec := recover(); rec != nil { | 		if rec := recover(); rec != nil { | ||||||
| 			err = PanicWrappedErr{panic: rec} | 			err = PanicWrappedErr{panic: rec, Stack: string(debug.Stack())} | ||||||
| 		} | 		} | ||||||
| 	}() | 	}() | ||||||
|  |  | ||||||
| @@ -27,7 +30,7 @@ func RunPanicSafe(fn func()) (err error) { | |||||||
| func RunPanicSafeR1(fn func() error) (err error) { | func RunPanicSafeR1(fn func() error) (err error) { | ||||||
| 	defer func() { | 	defer func() { | ||||||
| 		if rec := recover(); rec != nil { | 		if rec := recover(); rec != nil { | ||||||
| 			err = PanicWrappedErr{panic: rec} | 			err = PanicWrappedErr{panic: rec, Stack: string(debug.Stack())} | ||||||
| 		} | 		} | ||||||
| 	}() | 	}() | ||||||
|  |  | ||||||
| @@ -38,7 +41,7 @@ func RunPanicSafeR2[T1 any](fn func() (T1, error)) (r1 T1, err error) { | |||||||
| 	defer func() { | 	defer func() { | ||||||
| 		if rec := recover(); rec != nil { | 		if rec := recover(); rec != nil { | ||||||
| 			r1 = *new(T1) | 			r1 = *new(T1) | ||||||
| 			err = PanicWrappedErr{panic: rec} | 			err = PanicWrappedErr{panic: rec, Stack: string(debug.Stack())} | ||||||
| 		} | 		} | ||||||
| 	}() | 	}() | ||||||
|  |  | ||||||
| @@ -50,7 +53,7 @@ func RunPanicSafeR3[T1 any, T2 any](fn func() (T1, T2, error)) (r1 T1, r2 T2, er | |||||||
| 		if rec := recover(); rec != nil { | 		if rec := recover(); rec != nil { | ||||||
| 			r1 = *new(T1) | 			r1 = *new(T1) | ||||||
| 			r2 = *new(T2) | 			r2 = *new(T2) | ||||||
| 			err = PanicWrappedErr{panic: rec} | 			err = PanicWrappedErr{panic: rec, Stack: string(debug.Stack())} | ||||||
| 		} | 		} | ||||||
| 	}() | 	}() | ||||||
|  |  | ||||||
| @@ -63,7 +66,7 @@ func RunPanicSafeR4[T1 any, T2 any, T3 any](fn func() (T1, T2, T3, error)) (r1 T | |||||||
| 			r1 = *new(T1) | 			r1 = *new(T1) | ||||||
| 			r2 = *new(T2) | 			r2 = *new(T2) | ||||||
| 			r3 = *new(T3) | 			r3 = *new(T3) | ||||||
| 			err = PanicWrappedErr{panic: rec} | 			err = PanicWrappedErr{panic: rec, Stack: string(debug.Stack())} | ||||||
| 		} | 		} | ||||||
| 	}() | 	}() | ||||||
|  |  | ||||||
|   | |||||||
| @@ -27,10 +27,12 @@ func (a *AtomicBool) Get() bool { | |||||||
| 	return a.v | 	return a.v | ||||||
| } | } | ||||||
|  |  | ||||||
| func (a *AtomicBool) Set(value bool) { | func (a *AtomicBool) Set(value bool) bool { | ||||||
| 	a.lock.Lock() | 	a.lock.Lock() | ||||||
| 	defer a.lock.Unlock() | 	defer a.lock.Unlock() | ||||||
|  |  | ||||||
|  | 	oldValue := a.v | ||||||
|  |  | ||||||
| 	a.v = value | 	a.v = value | ||||||
|  |  | ||||||
| 	for k, v := range a.listener { | 	for k, v := range a.listener { | ||||||
| @@ -42,6 +44,8 @@ func (a *AtomicBool) Set(value bool) { | |||||||
| 			delete(a.listener, k) | 			delete(a.listener, k) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	return oldValue | ||||||
| } | } | ||||||
|  |  | ||||||
| func (a *AtomicBool) Wait(waitFor bool) { | func (a *AtomicBool) Wait(waitFor bool) { | ||||||
|   | |||||||
							
								
								
									
										28
									
								
								timeext/calendarweek.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								timeext/calendarweek.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,28 @@ | |||||||
|  | package timeext | ||||||
|  |  | ||||||
|  | import "time" | ||||||
|  |  | ||||||
|  | func WeekStart(year, week int) time.Time { | ||||||
|  |  | ||||||
|  | 	// https://stackoverflow.com/a/52303730/1761622 | ||||||
|  |  | ||||||
|  | 	// Start from the middle of the year: | ||||||
|  | 	t := time.Date(year, 7, 1, 0, 0, 0, 0, time.UTC) | ||||||
|  |  | ||||||
|  | 	// Roll back to Monday: | ||||||
|  | 	if wd := t.Weekday(); wd == time.Sunday { | ||||||
|  | 		t = t.AddDate(0, 0, -6) | ||||||
|  | 	} else { | ||||||
|  | 		t = t.AddDate(0, 0, -int(wd)+1) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// Difference in weeks: | ||||||
|  | 	_, w := t.ISOWeek() | ||||||
|  | 	t = t.AddDate(0, 0, (week-w)*7) | ||||||
|  |  | ||||||
|  | 	return t | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func WeekEnd(year, week int) time.Time { | ||||||
|  | 	return WeekStart(year, week).AddDate(0, 0, 7).Add(time.Duration(-1)) | ||||||
|  | } | ||||||
							
								
								
									
										25
									
								
								timeext/calendarweek_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								timeext/calendarweek_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | |||||||
|  | package timeext | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"gogs.mikescher.com/BlackForestBytes/goext/tst" | ||||||
|  | 	"testing" | ||||||
|  | 	"time" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | func TestWeekStart(t *testing.T) { | ||||||
|  |  | ||||||
|  | 	tst.AssertEqual(t, WeekStart(2018, 1).Format(time.RFC3339Nano), "2018-01-01T00:00:00Z") | ||||||
|  | 	tst.AssertEqual(t, WeekStart(2018, 2).Format(time.RFC3339Nano), "2018-01-08T00:00:00Z") | ||||||
|  | 	tst.AssertEqual(t, WeekStart(2019, 1).Format(time.RFC3339Nano), "2018-12-31T00:00:00Z") | ||||||
|  | 	tst.AssertEqual(t, WeekStart(2019, 2).Format(time.RFC3339Nano), "2019-01-07T00:00:00Z") | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestWeekEnd(t *testing.T) { | ||||||
|  |  | ||||||
|  | 	tst.AssertEqual(t, WeekEnd(2018, 1).Format(time.RFC3339Nano), "2018-01-07T23:59:59.999999999Z") | ||||||
|  | 	tst.AssertEqual(t, WeekEnd(2018, 2).Format(time.RFC3339Nano), "2018-01-14T23:59:59.999999999Z") | ||||||
|  | 	tst.AssertEqual(t, WeekEnd(2019, 1).Format(time.RFC3339Nano), "2019-01-06T23:59:59.999999999Z") | ||||||
|  | 	tst.AssertEqual(t, WeekEnd(2019, 2).Format(time.RFC3339Nano), "2019-01-13T23:59:59.999999999Z") | ||||||
|  |  | ||||||
|  | } | ||||||
| @@ -2,23 +2,59 @@ package tst | |||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"encoding/hex" | 	"encoding/hex" | ||||||
|  | 	"reflect" | ||||||
| 	"runtime/debug" | 	"runtime/debug" | ||||||
| 	"testing" | 	"testing" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| func AssertEqual[T comparable](t *testing.T, actual T, expected T) { | func AssertEqual[T comparable](t *testing.T, actual T, expected T) { | ||||||
|  | 	t.Helper() | ||||||
| 	if actual != expected { | 	if actual != expected { | ||||||
| 		t.Errorf("values differ: Actual: '%v', Expected: '%v'", actual, expected) | 		t.Errorf("values differ: Actual: '%v', Expected: '%v'", actual, expected) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| func AssertNotEqual[T comparable](t *testing.T, actual T, expected T) { | func AssertNotEqual[T comparable](t *testing.T, actual T, expected T) { | ||||||
|  | 	t.Helper() | ||||||
| 	if actual == expected { | 	if actual == expected { | ||||||
| 		t.Errorf("values do not differ: Actual: '%v', Expected: '%v'", actual, expected) | 		t.Errorf("values do not differ: Actual: '%v', Expected: '%v'", actual, expected) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func AssertDeepEqual[T any](t *testing.T, actual T, expected T) { | ||||||
|  | 	t.Helper() | ||||||
|  | 	if !reflect.DeepEqual(actual, expected) { | ||||||
|  | 		t.Errorf("values differ: Actual: '%v', Expected: '%v'", actual, expected) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func AssertSetDeepEqual[T any](t *testing.T, actual []T, expected []T) { | ||||||
|  | 	t.Helper() | ||||||
|  | 	if len(actual) != len(expected) { | ||||||
|  | 		t.Errorf("values differ in length: Actual (n=%d): '%v', Expected (n=%d): '%v'", len(actual), actual, len(expected), expected) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	for _, a := range expected { | ||||||
|  | 		found := false | ||||||
|  | 		for _, b := range actual { | ||||||
|  | 			found = found || reflect.DeepEqual(a, b) | ||||||
|  | 		} | ||||||
|  | 		if !found { | ||||||
|  | 			t.Errorf("values differ: Element '%v' not found. Actual: '%v', Expected: '%v'", a, actual, expected) | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func AssertNotDeepEqual[T any](t *testing.T, actual T, expected T) { | ||||||
|  | 	t.Helper() | ||||||
|  | 	if reflect.DeepEqual(actual, expected) { | ||||||
|  | 		t.Errorf("values do not differ: Actual: '%v', Expected: '%v'", actual, expected) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
| func AssertDeRefEqual[T comparable](t *testing.T, actual *T, expected T) { | func AssertDeRefEqual[T comparable](t *testing.T, actual *T, expected T) { | ||||||
|  | 	t.Helper() | ||||||
| 	if actual == nil { | 	if actual == nil { | ||||||
| 		t.Errorf("values differ: Actual: NIL, Expected: '%v'", expected) | 		t.Errorf("values differ: Actual: NIL, Expected: '%v'", expected) | ||||||
| 	} | 	} | ||||||
| @@ -28,6 +64,7 @@ func AssertDeRefEqual[T comparable](t *testing.T, actual *T, expected T) { | |||||||
| } | } | ||||||
|  |  | ||||||
| func AssertPtrEqual[T comparable](t *testing.T, actual *T, expected *T) { | func AssertPtrEqual[T comparable](t *testing.T, actual *T, expected *T) { | ||||||
|  | 	t.Helper() | ||||||
| 	if actual == nil && expected == nil { | 	if actual == nil && expected == nil { | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| @@ -47,6 +84,7 @@ func AssertPtrEqual[T comparable](t *testing.T, actual *T, expected *T) { | |||||||
| } | } | ||||||
|  |  | ||||||
| func AssertHexEqual(t *testing.T, expected string, actual []byte) { | func AssertHexEqual(t *testing.T, expected string, actual []byte) { | ||||||
|  | 	t.Helper() | ||||||
| 	actualStr := hex.EncodeToString(actual) | 	actualStr := hex.EncodeToString(actual) | ||||||
| 	if actualStr != expected { | 	if actualStr != expected { | ||||||
| 		t.Errorf("values differ: Actual: '%v', Expected: '%v'", actualStr, expected) | 		t.Errorf("values differ: Actual: '%v', Expected: '%v'", actualStr, expected) | ||||||
| @@ -54,18 +92,21 @@ func AssertHexEqual(t *testing.T, expected string, actual []byte) { | |||||||
| } | } | ||||||
|  |  | ||||||
| func AssertTrue(t *testing.T, value bool) { | func AssertTrue(t *testing.T, value bool) { | ||||||
|  | 	t.Helper() | ||||||
| 	if !value { | 	if !value { | ||||||
| 		t.Error("value should be true\n" + string(debug.Stack())) | 		t.Error("value should be true\n" + string(debug.Stack())) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| func AssertFalse(t *testing.T, value bool) { | func AssertFalse(t *testing.T, value bool) { | ||||||
|  | 	t.Helper() | ||||||
| 	if value { | 	if value { | ||||||
| 		t.Error("value should be false\n" + string(debug.Stack())) | 		t.Error("value should be false\n" + string(debug.Stack())) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| func AssertNoErr(t *testing.T, anerr error) { | func AssertNoErr(t *testing.T, anerr error) { | ||||||
|  | 	t.Helper() | ||||||
| 	if anerr != nil { | 	if anerr != nil { | ||||||
| 		t.Error("Function returned an error: " + anerr.Error() + "\n" + string(debug.Stack())) | 		t.Error("Function returned an error: " + anerr.Error() + "\n" + string(debug.Stack())) | ||||||
| 	} | 	} | ||||||
|   | |||||||
| @@ -116,3 +116,17 @@ func (c *Coll[TData]) Count(ctx context.Context, filter ct.Filter) (int64, error | |||||||
|  |  | ||||||
| 	return 0, nil | 	return 0, nil | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func (c *Coll[TData]) ListWithCount(ctx context.Context, filter ct.Filter, pageSize *int, inTok ct.CursorToken) ([]TData, ct.CursorToken, int64, error) { | ||||||
|  | 	// NOTE: Possible optimization: Cache count in CursorToken, then fetch count only on first page. | ||||||
|  | 	count, err := c.Count(ctx, filter) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, ct.CursorToken{}, 0, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	data, token, err := c.List(ctx, filter, pageSize, inTok) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, ct.CursorToken{}, 0, err | ||||||
|  | 	} | ||||||
|  | 	return data, token, count, nil | ||||||
|  | } | ||||||
|   | |||||||
| @@ -73,7 +73,7 @@ func (c *Coll[TData]) ReplaceOne(ctx context.Context, filterQuery bson.M, value | |||||||
| } | } | ||||||
|  |  | ||||||
| func (c *Coll[TData]) FindOneAndReplace(ctx context.Context, filterQuery bson.M, value TData) (TData, error) { | func (c *Coll[TData]) FindOneAndReplace(ctx context.Context, filterQuery bson.M, value TData) (TData, error) { | ||||||
| 	mongoRes := c.coll.FindOneAndUpdate(ctx, filterQuery, bson.M{"$set": value}, options.FindOneAndUpdate().SetReturnDocument(options.After)) | 	mongoRes := c.coll.FindOneAndReplace(ctx, filterQuery, value, options.FindOneAndReplace().SetReturnDocument(options.After)) | ||||||
| 	if err := mongoRes.Err(); err != nil { | 	if err := mongoRes.Err(); err != nil { | ||||||
| 		return *new(TData), exerr.Wrap(err, "mongo-query[find-one-and-update] failed"). | 		return *new(TData), exerr.Wrap(err, "mongo-query[find-one-and-update] failed"). | ||||||
| 			Str("collection", c.Name()). | 			Str("collection", c.Name()). | ||||||
|   | |||||||
| @@ -25,7 +25,7 @@ func (c *Coll[TData]) EnsureInitializedReflection(v TData) { | |||||||
|  |  | ||||||
| 	m := make(map[string]fullTypeRef) | 	m := make(map[string]fullTypeRef) | ||||||
|  |  | ||||||
| 	c.initFields("", rval, m, make([]int, 0)) | 	c.initFields("", rval.Type(), m, make([]int, 0), make([]reflect.Type, 0)) | ||||||
|  |  | ||||||
| 	c.implDataTypeMap[rval.Type()] = m | 	c.implDataTypeMap[rval.Type()] = m | ||||||
| } | } | ||||||
| @@ -50,20 +50,16 @@ func (c *Coll[TData]) init() { | |||||||
| 		c.implDataTypeMap = make(map[reflect.Type]map[string]fullTypeRef) | 		c.implDataTypeMap = make(map[reflect.Type]map[string]fullTypeRef) | ||||||
|  |  | ||||||
| 		v := reflect.ValueOf(example) | 		v := reflect.ValueOf(example) | ||||||
| 		c.initFields("", v, c.dataTypeMap, make([]int, 0)) | 		c.initFields("", v.Type(), c.dataTypeMap, make([]int, 0), make([]reflect.Type, 0)) | ||||||
|  |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| } | } | ||||||
|  |  | ||||||
| func (c *Coll[TData]) initFields(prefix string, rval reflect.Value, m map[string]fullTypeRef, idxarr []int) { | func (c *Coll[TData]) initFields(prefix string, rtyp reflect.Type, m map[string]fullTypeRef, idxarr []int, typesInPath []reflect.Type) { | ||||||
|  |  | ||||||
| 	rtyp := rval.Type() |  | ||||||
|  |  | ||||||
| 	for i := 0; i < rtyp.NumField(); i++ { | 	for i := 0; i < rtyp.NumField(); i++ { | ||||||
|  |  | ||||||
| 		rsfield := rtyp.Field(i) | 		rsfield := rtyp.Field(i) | ||||||
| 		rvfield := rval.Field(i) |  | ||||||
|  |  | ||||||
| 		if !rsfield.IsExported() { | 		if !rsfield.IsExported() { | ||||||
| 			continue | 			continue | ||||||
| @@ -91,21 +87,21 @@ func (c *Coll[TData]) initFields(prefix string, rval reflect.Value, m map[string | |||||||
| 		newIdxArr := langext.ArrCopy(idxarr) | 		newIdxArr := langext.ArrCopy(idxarr) | ||||||
| 		newIdxArr = append(newIdxArr, i) | 		newIdxArr = append(newIdxArr, i) | ||||||
|  |  | ||||||
| 		if langext.InArray("inline", bsontags) && rvfield.Kind() == reflect.Struct { | 		if langext.InArray("inline", bsontags) && rsfield.Type.Kind() == reflect.Struct { | ||||||
|  |  | ||||||
| 			// pass-through field | 			// pass-through field | ||||||
| 			c.initFields(prefix, rvfield, m, newIdxArr) | 			c.initFields(prefix, rsfield.Type, m, newIdxArr, typesInPath) | ||||||
|  |  | ||||||
| 		} else { | 		} else { | ||||||
|  |  | ||||||
| 			if rvfield.Type().Kind() == reflect.Pointer { | 			if rsfield.Type.Kind() == reflect.Pointer { | ||||||
|  |  | ||||||
| 				m[fullKey] = fullTypeRef{ | 				m[fullKey] = fullTypeRef{ | ||||||
| 					IsPointer:      true, | 					IsPointer:      true, | ||||||
| 					RealType:       rvfield.Type(), | 					RealType:       rsfield.Type, | ||||||
| 					Kind:           rvfield.Type().Elem().Kind(), | 					Kind:           rsfield.Type.Elem().Kind(), | ||||||
| 					Type:           rvfield.Type().Elem(), | 					Type:           rsfield.Type.Elem(), | ||||||
| 					UnderlyingType: reflectext.Underlying(rvfield.Type().Elem()), | 					UnderlyingType: reflectext.Underlying(rsfield.Type.Elem()), | ||||||
| 					Name:           rsfield.Name, | 					Name:           rsfield.Name, | ||||||
| 					Index:          newIdxArr, | 					Index:          newIdxArr, | ||||||
| 				} | 				} | ||||||
| @@ -114,20 +110,37 @@ func (c *Coll[TData]) initFields(prefix string, rval reflect.Value, m map[string | |||||||
|  |  | ||||||
| 				m[fullKey] = fullTypeRef{ | 				m[fullKey] = fullTypeRef{ | ||||||
| 					IsPointer:      false, | 					IsPointer:      false, | ||||||
| 					RealType:       rvfield.Type(), | 					RealType:       rsfield.Type, | ||||||
| 					Kind:           rvfield.Type().Kind(), | 					Kind:           rsfield.Type.Kind(), | ||||||
| 					Type:           rvfield.Type(), | 					Type:           rsfield.Type, | ||||||
| 					UnderlyingType: reflectext.Underlying(rvfield.Type()), | 					UnderlyingType: reflectext.Underlying(rsfield.Type), | ||||||
| 					Name:           rsfield.Name, | 					Name:           rsfield.Name, | ||||||
| 					Index:          newIdxArr, | 					Index:          newIdxArr, | ||||||
| 				} | 				} | ||||||
|  |  | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			if rvfield.Kind() == reflect.Struct { | 			if rsfield.Type.Kind() == reflect.Struct { | ||||||
| 				c.initFields(fullKey+".", rvfield, m, newIdxArr) | 				c.initFields(fullKey+".", rsfield.Type, m, newIdxArr, typesInPath) | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
|  | 			if rsfield.Type.Kind() == reflect.Pointer && rsfield.Type.Elem().Kind() == reflect.Struct { | ||||||
|  | 				innerType := rsfield.Type.Elem() | ||||||
|  |  | ||||||
|  | 				// check if there is recursion | ||||||
|  | 				recursion := false | ||||||
|  | 				for _, typ := range typesInPath { | ||||||
|  | 					recursion = recursion || (typ == innerType) | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  | 				if !recursion { | ||||||
|  | 					// Store all seen types before that deref a pointer to prevent endless recursion | ||||||
|  | 					newTypesInPath := make([]reflect.Type, len(typesInPath)) | ||||||
|  | 					copy(newTypesInPath, typesInPath) | ||||||
|  | 					newTypesInPath = append(newTypesInPath, rtyp) | ||||||
|  | 					c.initFields(fullKey+".", innerType, m, newIdxArr, newTypesInPath) | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 	} | 	} | ||||||
|   | |||||||
| @@ -23,6 +23,9 @@ func TestReflectionGetFieldType(t *testing.T) { | |||||||
| 		Sub   struct { | 		Sub   struct { | ||||||
| 			A string `bson:"a"` | 			A string `bson:"a"` | ||||||
| 		} `bson:"sub"` | 		} `bson:"sub"` | ||||||
|  | 		SubPtr *struct { | ||||||
|  | 			A string `bson:"a"` | ||||||
|  | 		} `bson:"subPtr"` | ||||||
| 		Str   string                  `bson:"str"` | 		Str   string                  `bson:"str"` | ||||||
| 		Ptr   *int                    `bson:"ptr"` | 		Ptr   *int                    `bson:"ptr"` | ||||||
| 		MDate rfctime.RFC3339NanoTime `bson:"mdate"` | 		MDate rfctime.RFC3339NanoTime `bson:"mdate"` | ||||||
| @@ -43,6 +46,11 @@ func TestReflectionGetFieldType(t *testing.T) { | |||||||
| 		}{ | 		}{ | ||||||
| 			A: "2", | 			A: "2", | ||||||
| 		}, | 		}, | ||||||
|  | 		SubPtr: &struct { | ||||||
|  | 			A string `bson:"a"` | ||||||
|  | 		}{ | ||||||
|  | 			A: "4", | ||||||
|  | 		}, | ||||||
| 		Str:   "3", | 		Str:   "3", | ||||||
| 		Ptr:   langext.Ptr(4), | 		Ptr:   langext.Ptr(4), | ||||||
| 		MDate: t1, | 		MDate: t1, | ||||||
| @@ -82,6 +90,12 @@ func TestReflectionGetFieldType(t *testing.T) { | |||||||
| 	tst.AssertEqual(t, gft("sub.a").IsPointer, false) | 	tst.AssertEqual(t, gft("sub.a").IsPointer, false) | ||||||
| 	tst.AssertEqual(t, gfv("sub.a").(string), "2") | 	tst.AssertEqual(t, gfv("sub.a").(string), "2") | ||||||
|  |  | ||||||
|  | 	tst.AssertEqual(t, gft("subPtr.a").Kind.String(), "string") | ||||||
|  | 	tst.AssertEqual(t, gft("subPtr.a").Type.String(), "string") | ||||||
|  | 	tst.AssertEqual(t, gft("subPtr.a").Name, "A") | ||||||
|  | 	tst.AssertEqual(t, gft("subPtr.a").IsPointer, false) | ||||||
|  | 	tst.AssertEqual(t, gfv("subPtr.a").(string), "4") | ||||||
|  |  | ||||||
| 	tst.AssertEqual(t, gft("str").Kind.String(), "string") | 	tst.AssertEqual(t, gft("str").Kind.String(), "string") | ||||||
| 	tst.AssertEqual(t, gft("str").Type.String(), "string") | 	tst.AssertEqual(t, gft("str").Type.String(), "string") | ||||||
| 	tst.AssertEqual(t, gft("str").Name, "Str") | 	tst.AssertEqual(t, gft("str").Name, "Str") | ||||||
| @@ -99,16 +113,25 @@ func TestReflectionGetTokenValueAsMongoType(t *testing.T) { | |||||||
|  |  | ||||||
| 	type IDType string | 	type IDType string | ||||||
|  |  | ||||||
|  | 	type RecurseiveType struct { | ||||||
|  | 		Other int             `bson:"other"` | ||||||
|  | 		Inner *RecurseiveType `bson:"inner"` | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	type TestData struct { | 	type TestData struct { | ||||||
| 		ID    IDType    `bson:"_id"` | 		ID    IDType    `bson:"_id"` | ||||||
| 		CDate time.Time `bson:"cdate"` | 		CDate time.Time `bson:"cdate"` | ||||||
| 		Sub   struct { | 		Sub   struct { | ||||||
| 			A string `bson:"a"` | 			A string `bson:"a"` | ||||||
| 		} `bson:"sub"` | 		} `bson:"sub"` | ||||||
|  | 		SubPtr *struct { | ||||||
|  | 			A string `bson:"a"` | ||||||
|  | 		} `bson:"subPtr"` | ||||||
| 		Str   string                  `bson:"str"` | 		Str   string                  `bson:"str"` | ||||||
| 		Ptr   *int                    `bson:"ptr"` | 		Ptr   *int                    `bson:"ptr"` | ||||||
| 		Num   int                     `bson:"num"` | 		Num   int                     `bson:"num"` | ||||||
| 		MDate rfctime.RFC3339NanoTime `bson:"mdate"` | 		MDate rfctime.RFC3339NanoTime `bson:"mdate"` | ||||||
|  | 		Rec   RecurseiveType          `bson:"rec"` | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	coll := W[TestData](&mongo.Collection{}) | 	coll := W[TestData](&mongo.Collection{}) | ||||||
| @@ -130,6 +153,9 @@ func TestReflectionGetTokenValueAsMongoType(t *testing.T) { | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	tst.AssertEqual(t, gtvasmt("hello", "str").(string), "hello") | 	tst.AssertEqual(t, gtvasmt("hello", "str").(string), "hello") | ||||||
|  | 	tst.AssertEqual(t, gtvasmt("hello", "sub.a").(string), "hello") | ||||||
|  | 	tst.AssertEqual(t, gtvasmt("hello", "subPtr.a").(string), "hello") | ||||||
|  | 	tst.AssertEqual(t, gtvasmt("4", "rec.other").(int), 4) | ||||||
| 	tst.AssertEqual(t, gtvasmt("4", "num").(int), 4) | 	tst.AssertEqual(t, gtvasmt("4", "num").(int), 4) | ||||||
| 	tst.AssertEqual(t, gtvasmt("asdf", "_id").(IDType), "asdf") | 	tst.AssertEqual(t, gtvasmt("asdf", "_id").(IDType), "asdf") | ||||||
| 	tst.AssertEqual(t, gtvasmt("", "ptr").(*int), nil) | 	tst.AssertEqual(t, gtvasmt("", "ptr").(*int), nil) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user