{"id":13655206,"url":"https://github.com/wroge/scan","last_synced_at":"2025-04-14T19:43:38.551Z","repository":{"id":59047683,"uuid":"535050598","full_name":"wroge/scan","owner":"wroge","description":"scan sql rows into any type powered by generics","archived":false,"fork":false,"pushed_at":"2024-03-08T13:18:34.000Z","size":95,"stargazers_count":63,"open_issues_count":0,"forks_count":3,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-10-02T03:03:41.901Z","etag":null,"topics":["database","db","generics","go","golang","mapping","rows","scan","scanner","sql"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/wroge.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2022-09-10T16:14:04.000Z","updated_at":"2024-08-19T13:33:18.000Z","dependencies_parsed_at":"2024-03-08T14:44:47.451Z","dependency_job_id":null,"html_url":"https://github.com/wroge/scan","commit_stats":null,"previous_names":[],"tags_count":17,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wroge%2Fscan","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wroge%2Fscan/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wroge%2Fscan/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wroge%2Fscan/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/wroge","download_url":"https://codeload.github.com/wroge/scan/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":219843335,"owners_count":16556507,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["database","db","generics","go","golang","mapping","rows","scan","scanner","sql"],"created_at":"2024-08-02T03:00:59.547Z","updated_at":"2024-10-15T16:04:46.932Z","avatar_url":"https://github.com/wroge.png","language":"Go","readme":"Take a look at [github.com/wroge/esquel](https://github.com/wroge/esquel). \n\n\u003cbr\u003e\n\n[![go.dev reference](https://img.shields.io/badge/go.dev-reference-007d9c?logo=go\u0026logoColor=white)](https://pkg.go.dev/github.com/wroge/scan)\n[![Go Report Card](https://goreportcard.com/badge/github.com/wroge/scan)](https://goreportcard.com/report/github.com/wroge/scan)\n![golangci-lint](https://github.com/wroge/scan/workflows/golangci-lint/badge.svg)\n[![codecov](https://codecov.io/gh/wroge/scan/branch/main/graph/badge.svg?token=SBSedMOGHR)](https://codecov.io/gh/wroge/scan)\n[![GitHub tag (latest SemVer)](https://img.shields.io/github/tag/wroge/scan.svg?style=social)](https://github.com/wroge/scan/tags)\n\n# Scan\n\nThis package offers a convenient and flexible way to scan SQL rows into any type, leveraging the power of generics.\n\n## Features\n\n- **Efficient and Reusable**: Avoid repetitive code and define the column-mapping in one place.\n- **Auto Closing**: No need to worry about resource leaks.\n- **No Reflection**: Faster than reflection based mappers.\n- **Robust Error Handling**: Best practices for managing errors.\n\n## Usage\n\n```go\nimport \"github.com/wroge/scan\"\n\ntype Author struct {\n\tID   int64\n\tName string\n}\n\ntype Post struct {\n\tID      int64\n\tTitle   string\n\tAuthors []Author\n}\n\n// Define mapping of database columns to struct fields.\nvar columns = scan.Columns[Post]{\n\t// Map the 'id' column to the 'ID' field in the 'Post' struct.\n\t// Uses the 'scan.Any' function for direct assignment without additional processing.\n\t\"id\": scan.Any(func(p *Post, id int64) { p.ID = id }),\n\n\t// Map the 'title' column to the 'Title' field in the 'Post' struct.\n\t// The 'scan.Null' function allows handling of nullable database columns.\n\t// If the 'title' column is null, 'default title' is used as the value.\n\t\"title\": scan.Null(\"default title\", func(p *Post, title string) { p.Title = title }),\n\n\t// Map the 'authors' column, expected to be in JSON format, to the 'Authors' field in the 'Post' struct.\n\t// The 'scan.JSON' function automatically handles unmarshalling of the JSON data into the 'Author' struct slice.\n\t\"authors\": scan.JSON(func(p *Post, authors []Author) { p.Authors = authors }),\n\n\t// Or you could create a custom scanner with this function.\n\t// \"column\": scan.Func[Post, V](func(p *Post, value V) error {\n\t// \treturn nil\n\t// }),\n}\n\nrows, err := db.Query(\"SELECT ...\")\n// handle error\n```\n\n#### Scanning all rows\n\n```go \nposts, err := scan.All(rows, columns)\n// handle error\n```\n\n#### Scanning the first row\n\n```go \npost, err := scan.First(rows, columns)\nif err != nil {\n\tif errors.Is(err, scan.ErrNoRows) {\n\t\t// handle no rows\n\t}\n\n\t// handle other error\n}\n```\n\n#### Scanning exactly one row\n\n```go \npost, err := scan.One(rows, columns)\nif err != nil {\n\tif errors.Is(err, scan.ErrTooManyRows) {\n\t\t// handle too many rows\n\t\t// post is valid\n\t}\n\n\tif errors.Is(err, scan.ErrNoRows) {\n\t\t// handle no rows\n\t}\n\n\t// handle other error\n}\n```\n\n#### Scanning a limited number of rows\n\n```go \nposts, err := scan.Limit(10, rows, columns)\nif err != nil {\n\tif errors.Is(err, scan.ErrTooManyRows) {\n\t\t// ignore if result set has more than 10 rows\n\t\t// len(posts) == 10\n\t}\n\n\t// handle other error\n}\n```\n\n#### Using the Iterator directly\n\n```go \niter, err := scan.Iter(rows, columns)\n// handle error\n\ndefer iter.Close()\n\nfor iter.Next() {\n\tvar post Post\n\n\terr = iter.Scan(\u0026post)\n\t// handle error\n\n\t// Or use the Value method:\n\tpost, err := iter.Value()\n\t// handle error\n}\n```\n","funding_links":[],"categories":["公用事业公司","Utilities","Programming Languages"],"sub_categories":["实用程序/Miscellaneous","Utility/Miscellaneous","Golang"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwroge%2Fscan","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwroge%2Fscan","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwroge%2Fscan/lists"}