{"id":34697134,"url":"https://github.com/yaitoo/sqle","last_synced_at":"2026-03-13T16:31:05.692Z","repository":{"id":220159050,"uuid":"750911193","full_name":"yaitoo/sqle","owner":"yaitoo","description":"A SQL-first/ORM-like Golang SQL package.","archived":false,"fork":false,"pushed_at":"2025-12-01T08:12:02.000Z","size":163,"stargazers_count":27,"open_issues_count":0,"forks_count":2,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-12-03T18:59:25.809Z","etag":null,"topics":["consistent-hash","database","go","golang","gorm","migrate","migration","mysql","orm","orm-like","postgress","querybuilder","rotate","rotation","sharding","sql","sqlbuilder","sqlite3","tsql"],"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/yaitoo.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","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,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2024-01-31T15:10:28.000Z","updated_at":"2025-12-01T08:11:18.000Z","dependencies_parsed_at":"2024-03-11T04:32:55.468Z","dependency_job_id":"ab997a70-0794-4742-8fee-b3b2935a4461","html_url":"https://github.com/yaitoo/sqle","commit_stats":null,"previous_names":["yaitoo/sqle"],"tags_count":20,"template":false,"template_full_name":null,"purl":"pkg:github/yaitoo/sqle","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yaitoo%2Fsqle","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yaitoo%2Fsqle/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yaitoo%2Fsqle/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yaitoo%2Fsqle/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/yaitoo","download_url":"https://codeload.github.com/yaitoo/sqle/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yaitoo%2Fsqle/sbom","scorecard":{"id":1236625,"data":{"date":"2025-07-07","repo":{"name":"github.com/yaitoo/sqle","commit":"f2035b4d05c9f6b5864f4505d53a253ed1965a2f"},"scorecard":{"version":"v5.2.1-18-gbb9c347d","commit":"bb9c347dff6349d986baab6578a46d68a5524c62"},"score":4.3,"checks":[{"name":"Maintained","score":0,"reason":"1 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/bb9c347dff6349d986baab6578a46d68a5524c62/docs/checks.md#maintained"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/bb9c347dff6349d986baab6578a46d68a5524c62/docs/checks.md#packaging"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/bb9c347dff6349d986baab6578a46d68a5524c62/docs/checks.md#dangerous-workflow"}},{"name":"Code-Review","score":0,"reason":"Found 0/28 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/bb9c347dff6349d986baab6578a46d68a5524c62/docs/checks.md#code-review"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Info: jobLevel 'actions' permission set to 'read': .github/workflows/codeql.yml:37","Info: jobLevel 'contents' permission set to 'read': .github/workflows/codeql.yml:38","Warn: no topLevel permission defined: .github/workflows/codeql.yml:1","Warn: no topLevel permission defined: .github/workflows/tests.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/bb9c347dff6349d986baab6578a46d68a5524c62/docs/checks.md#token-permissions"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/bb9c347dff6349d986baab6578a46d68a5524c62/docs/checks.md#binary-artifacts"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/codeql.yml:51: update your workflow using https://app.stepsecurity.io/secureworkflow/yaitoo/sqle/codeql.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/codeql.yml:55: update your workflow using https://app.stepsecurity.io/secureworkflow/yaitoo/sqle/codeql.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/codeql.yml:69: update your workflow using https://app.stepsecurity.io/secureworkflow/yaitoo/sqle/codeql.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/codeql.yml:82: update your workflow using https://app.stepsecurity.io/secureworkflow/yaitoo/sqle/codeql.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/tests.yml:22: update your workflow using https://app.stepsecurity.io/secureworkflow/yaitoo/sqle/tests.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/tests.yml:24: update your workflow using https://app.stepsecurity.io/secureworkflow/yaitoo/sqle/tests.yml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/tests.yml:28: update your workflow using https://app.stepsecurity.io/secureworkflow/yaitoo/sqle/tests.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/tests.yml:36: update your workflow using https://app.stepsecurity.io/secureworkflow/yaitoo/sqle/tests.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/tests.yml:38: update your workflow using https://app.stepsecurity.io/secureworkflow/yaitoo/sqle/tests.yml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/tests.yml:46: update your workflow using https://app.stepsecurity.io/secureworkflow/yaitoo/sqle/tests.yml/main?enable=pin","Info:   0 out of   8 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   2 third-party GitHubAction dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/bb9c347dff6349d986baab6578a46d68a5524c62/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/bb9c347dff6349d986baab6578a46d68a5524c62/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/bb9c347dff6349d986baab6578a46d68a5524c62/docs/checks.md#security-policy"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/bb9c347dff6349d986baab6578a46d68a5524c62/docs/checks.md#license"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/bb9c347dff6349d986baab6578a46d68a5524c62/docs/checks.md#fuzzing"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/bb9c347dff6349d986baab6578a46d68a5524c62/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":-1,"reason":"internal error: error during branchesHandler.setup: internal error: githubv4.Query: Resource not accessible by integration","details":null,"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/bb9c347dff6349d986baab6578a46d68a5524c62/docs/checks.md#branch-protection"}},{"name":"SAST","score":7,"reason":"SAST tool detected but not run on all commits","details":["Info: SAST configuration detected: CodeQL","Warn: 1 commits out of 26 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/bb9c347dff6349d986baab6578a46d68a5524c62/docs/checks.md#sast"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/bb9c347dff6349d986baab6578a46d68a5524c62/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-09-01T02:34:22.979Z","repository_id":220159050,"created_at":"2025-09-01T02:34:22.979Z","updated_at":"2025-09-01T02:34:22.979Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30470998,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-13T11:00:43.441Z","status":"ssl_error","status_checked_at":"2026-03-13T11:00:23.173Z","response_time":60,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":["consistent-hash","database","go","golang","gorm","migrate","migration","mysql","orm","orm-like","postgress","querybuilder","rotate","rotation","sharding","sql","sqlbuilder","sqlite3","tsql"],"created_at":"2025-12-24T22:38:10.478Z","updated_at":"2026-03-13T16:31:05.683Z","avatar_url":"https://github.com/yaitoo.png","language":"Go","readme":"# SQLE\nA SQL-First/ORM-like Golang SQL enhanced package.\n\n![License](https://img.shields.io/badge/license-MIT-green.svg)\n[![Tests](https://github.com/yaitoo/sqle/actions/workflows/tests.yml/badge.svg)](https://github.com/yaitoo/sqle/actions/workflows/tests.yml)\n[![Go Reference](https://pkg.go.dev/badge/github.com/yaitoo/sqle.svg)](https://pkg.go.dev/github.com/yaitoo/sqle)\n[![Codecov](https://codecov.io/gh/yaitoo/sqle/branch/main/graph/badge.svg)](https://codecov.io/gh/yaitoo/sqle)\n[![GitHub Release](https://img.shields.io/github/v/release/yaitoo/sqle)](https://github.com/yaitoo/sqle/blob/main/CHANGELOG.md)\n[![Go Report Card](https://goreportcard.com/badge/yaitoo/sqle)](http://goreportcard.com/report/yaitoo/sqle)\n\nThe SQLE package provides extensions to Go’s built-in `database/sql` package for more efficient, comprehensive interactions with databases in Go. The SQLE package is backward-compatible and extendable, so you can easily use it with the database/sql package.\n\nThe SQLE package takes the sql-first approach and provides functionalities for marshaling rows into struct, map,slice and primitive types.\n\nThe SQLE package also provides functionalities for schema auto migration, logging, contexts, prepared statements, advanced database operations like sharding, and much more.\n\nYou’ll find the SQLE package useful if you’re not a fan of full-featured ORMs and you prefer to use the database/sql package with extra support and functionalities.\n\n## Features\n- Works with any database engine(eg MySQL, Postgres, SQLite...etc) by [Go-MySQL-Driver](https://github.com/go-sql-driver/mysql/)\n- [ORM-like](rows_test.go) experience using good old SQL. SQLE supports structs, maps, primitive types, and\n  slices of map/structs/primitive types.\n- [SQLBuilder](sqlbuilder_test.go)\n- 100% compatible drop-in replacement of \"database/sql\". Code is really easy to migrate from `database/sql` to `SQLE`. see [examples](row_test.go)\n- [ShardID](shardid/README.md) is a `snowflakes-like` distributed unique identifier with extended metadata : worker, table rotation and database sharding, and sortable by time\n- Table AutoRotation\n- Database AutoSharding\n- MapR Query\n- [Migration](migrate/migrator_test.go): migrate database with sql files organized in filesystem. it supports to migrate table and multiple rotated tables on all sharding database instances.\n\n## Tutorials\n\u003e All examples on https://go.dev/doc/tutorial/database-access can directly work with `sqle.DB` instance.\n\u003e\n\n\u003e See full examples on https://github.com/yaitoo/auth\n\u003e\n\n### Install SQLE\n- install latest commit from `main` branch\n```sh\ngo get github.com/yaitoo/sqle@main\n```\n\n- install latest release\n```sh\ngo get github.com/yaitoo/sqle@latest\n```\n\n### Connecting to a Database\nSQLE directly connects to a database by `sql.DB` instance.\n```go\n    driver := viper.GetString(\"db.driver\")\n    dsn := viper.GetString(\"db.dsn\")\n\n    var db *sqle.DB\n\n    switch driver {\n        case \"sqlite\":\n            sqldb, err := sql.Open(\"sqlite3\", \"file:\"+dsn+\"?cache=shared\")\n            if err != nil {\n                panic(fmt.Sprintf(\"db: failed to open sqlite database %s\", dsn))\n            }\n\n            db = sqle.Open(sqldb)\n\n\n        case \"mysql\":\n            sqldb, err := sql.Open(\"mysql\", dsn)\n            if err != nil {\n                panic(fmt.Sprintf(\"db: failed to open mysql database %s\", dsn))\n            }\n\n            db = sqle.Open(sqldb)\n\n        default:\n            panic(fmt.Sprintf(\"db: driver %s is not supported yet\", driver))\n    }\n\n    if  err := db.Ping(); err == nil {\n        panic(\"db: database is unreachable\")\n    }\n```\n\n### Create\n- create album by sql\n```go\nfunc addAlbum(alb Album) (int64, error) {\n    result, err := db.Exec(\"INSERT INTO album (title, artist, price) VALUES (?, ?, ?)\", alb.Title, alb.Artist, alb.Price)\n    if err != nil {\n        return 0, fmt.Errorf(\"addAlbum: %v\", err)\n    }\n    id, err := result.LastInsertId()\n    if err != nil {\n        return 0, fmt.Errorf(\"addAlbum: %v\", err)\n    }\n    return id, nil\n}\n```\n- create album by named sql statement\n```go\nfunc addAlbum(alb Album) (int64, error) {\n    cmd := sqle.New(\"INSERT INTO album (title, artist, price) VALUES ({title}, {artist}, {price}\").\n      Param(\"title\", alb.Title).\n      Param(\"artist\", alb.Artist).\n      Param(\"price\", alb.Price)\n\n    result, err := db.ExecBuilder(context.TODO(),cmd)\n    if err != nil {\n        return 0, fmt.Errorf(\"addAlbum: %v\", err)\n    }\n    id, err := result.LastInsertId()\n    if err != nil {\n        return 0, fmt.Errorf(\"addAlbum: %v\", err)\n    }\n    return id, nil\n}\n```\n- create album by `InsertBuilder` feature\n```go\nfunc addAlbum(alb Album) (int64, error) {\n    cmd := sqle.New().Insert(\"album\").\n      Set(\"title\", alb.Title).\n      Set(\"artist\", alb.Artist).\n      Set(\"price\", alb.Price).\n      End()\n\n    result, err := db.ExecBuilder(context.TODO(),cmd)\n    if err != nil {\n        return 0, fmt.Errorf(\"addAlbum: %v\", err)\n    }\n    id, err := result.LastInsertId()\n    if err != nil {\n        return 0, fmt.Errorf(\"addAlbum: %v\", err)\n    }\n    return id, nil\n}\n```\n- create album by `map` object\n```go\nfunc addAlbum(alb Album) (int64, error) {\n    inputs := map[string]any{\n      \"title\":alb.Title,\n      \"artist\":alb.Artist,\n      \"price\":alb.Price,\n    }\n\n    cmd := sqle.New().Insert(\"album\").\n      SetMap(inputs)\n      End()\n\n    result, err := db.ExecBuilder(context.TODO(),cmd)\n    if err != nil {\n        return 0, fmt.Errorf(\"addAlbum: %v\", err)\n    }\n    id, err := result.LastInsertId()\n    if err != nil {\n        return 0, fmt.Errorf(\"addAlbum: %v\", err)\n    }\n    return id, nil\n}\n```\n- create album by ORM-like feature\n```go\nfunc addAlbum(alb Album) (int64, error) {\n    cmd := sqle.New().Insert(\"album\").\n      SetModel(alb).\n      End()\n\n    result, err := db.ExecBuilder(context.TODO(),cmd)\n    if err != nil {\n        return 0, fmt.Errorf(\"addAlbum: %v\", err)\n    }\n    id, err := result.LastInsertId()\n    if err != nil {\n        return 0, fmt.Errorf(\"addAlbum: %v\", err)\n    }\n    return id, nil\n}\n```\n\n### Query\n#### query for multiple rows\n- query albums by sql\n```go\nfunc albumsByArtist(name string) ([]Album, error) {\n    // An albums slice to hold data from returned rows.\n    var albums []Album\n\n    rows, err := db.Query(\"SELECT * FROM album WHERE artist = ?\", name)\n    if err != nil {\n        return nil, fmt.Errorf(\"albumsByArtist %q: %v\", name, err)\n    }\n    defer rows.Close()\n    // Loop through rows, using Scan to assign column data to struct fields.\n    for rows.Next() {\n        var alb Album\n        if err := rows.Scan(\u0026alb.ID, \u0026alb.Title, \u0026alb.Artist, \u0026alb.Price); err != nil {\n            return nil, fmt.Errorf(\"albumsByArtist %q: %v\", name, err)\n        }\n        albums = append(albums, alb)\n    }\n    if err := rows.Err(); err != nil {\n        return nil, fmt.Errorf(\"albumsByArtist %q: %v\", name, err)\n    }\n    return albums, nil\n}\n```\n- query albums by named sql statement\n```go\nfunc albumsByArtist(name string) ([]Album, error) {\n    // An albums slice to hold data from returned rows.\n    var albums []Album\n\n    cmd := sql.New(\"SELECT * FROM album WHERE artist = {artist}\").\n    Param(\"artist\",name)\n\n    rows, err := db.QueryBuilder(context.TODO(), cmd)\n    if err != nil {\n        return nil, fmt.Errorf(\"albumsByArtist %q: %v\", name, err)\n    }\n    defer rows.Close()\n    // Loop through rows, using Scan to assign column data to struct fields.\n    for rows.Next() {\n        var alb Album\n        if err := rows.Scan(\u0026alb.ID, \u0026alb.Title, \u0026alb.Artist, \u0026alb.Price); err != nil {\n            return nil, fmt.Errorf(\"albumsByArtist %q: %v\", name, err)\n        }\n        albums = append(albums, alb)\n    }\n    if err := rows.Err(); err != nil {\n        return nil, fmt.Errorf(\"albumsByArtist %q: %v\", name, err)\n    }\n    return albums, nil\n}\n```\n- query albums by `WhereBuilder` feature\n```go\nfunc albumsByArtist(name string) ([]Album, error) {\n    // An albums slice to hold data from returned rows.\n    var albums []Album\n\n    cmd := sql.New(\"SELECT * FROM album\").Where().\n    If(name != \"\").And(\"artist = {artist}\").Param(\"artist\",name)\n\n    err := db.QueryBuilder(context.TODO(), cmd).Bind(\u0026albums)\n    if err != nil {\n        return nil, fmt.Errorf(\"albumsByArtist %q: %v\", name, err)\n    }\n\n    return albums, nil\n}\n```\n\n- query albums by ORM-like feature\n```go\nfunc albumsByArtist(name string) ([]Album, error) {\n    // An albums slice to hold data from returned rows.\n    var albums []Album\n\n    cmd := sql.New().Select(\"album\").Where().\n        If(name != \"\").And(\"artist = {artist}\").\n        Param(\"artist\",name)\n\n    err := db.QueryBuilder(context.TODO(), cmd).Bind(\u0026albums)\n    if err != nil {\n        return nil, fmt.Errorf(\"albumsByArtist %q: %v\", name, err)\n    }\n\n    return albums, nil\n}\n```\n\n#### query for a single row\n- query album by sql\n```go\nfunc albumByID(id int64) (Album, error) {\n    // An album to hold data from the returned row.\n    var alb Album\n\n    row := db.QueryRow(\"SELECT * FROM album WHERE id = ?\", id)\n    if err := row.Scan(\u0026alb.ID, \u0026alb.Title, \u0026alb.Artist, \u0026alb.Price); err != nil {\n        if err == sql.ErrNoRows {\n            return alb, fmt.Errorf(\"albumsById %d: no such album\", id)\n        }\n        return alb, fmt.Errorf(\"albumsById %d: %v\", id, err)\n    }\n    return alb, nil\n}\n```\n\n- query album by named sql statement\n```go\nfunc albumByID(id int64) (Album, error) {\n    // An album to hold data from the returned row.\n    var alb Album\n    cmd := sqle.New(\"SELECT * FROM album\").\n        Where(\"id = {id}\").\n        Param(\"id\",id)\n\n    row := db.QueryRowBuilder(context.TODO(),cmd)\n    if err := row.Scan(\u0026alb.ID, \u0026alb.Title, \u0026alb.Artist, \u0026alb.Price); err != nil {\n        if err == sql.ErrNoRows {\n            return alb, fmt.Errorf(\"albumsById %d: no such album\", id)\n        }\n        return alb, fmt.Errorf(\"albumsById %d: %v\", id, err)\n    }\n    return alb, nil\n}\n```\n\n- query album by ORM-like feature\n```go\nfunc albumByID(id int64) (Album, error) {\n    // An album to hold data from the returned row.\n    var alb Album\n    cmd := sqle.New().Select(\"album\").\n        Where(\"id = {id}\").\n        Param(\"id\",id)\n\n    err := db.QueryRowBuilder(context.TODO(),cmd).Bind(\u0026alb)\n    if err != nil {\n        if err == sql.ErrNoRows {\n            return alb, fmt.Errorf(\"albumsById %d: no such album\", id)\n        }\n        return alb, fmt.Errorf(\"albumsById %d: %v\", id, err)\n    }\n    return alb, nil\n}\n```\n\n### Update\n- update album by sql\n```go\nfunc updateAlbum(alb Album) error {\n    _, err := db.Exec(\"UPDATE album SET title=?, artist=?, price=? WHERE id=?\", alb.Title, alb.Artist, alb.Price, alb.ID)\n    if err != nil {\n        return 0, fmt.Errorf(\"addAlbum: %v\", err)\n    }\n    return err\n}\n```\n\n- update album by named sql statement\n```go\nfunc updateAlbum(alb Album) error {\n    cmd := sqle.New(\"UPDATE album SET title={title}, artist={artist}, price={price} WHERE id={id}\").\n        Param(\"title\", alb.Title).\n        Param(\"artist\", alb.Artist).\n        Param(\"price\", alb.Price).\n        Param(\"id\", alb.ID)\n\n    _, err := db.ExecBuilder(context.TODO(), cmd)\n    if err != nil {\n        return 0, fmt.Errorf(\"addAlbum: %v\", err)\n    }\n\n    return err\n}\n```\n\n- update album by `UpdateBuilder` feature\n```go\nfunc updateAlbum(alb Album) error {\n    cmd := sqle.New().Update(\"album\").\n        Set(\"title\", alb.Title).\n        Set(\"artist\", alb.Artist).\n        Set(\"price\", alb.Price).\n        Set(\"id\", alb.ID).\n        Where(\"id={id}\").Param(\"id\", alb.ID)\n\n    _, err := db.ExecBuilder(context.TODO(), cmd)\n    if err != nil {\n        return 0, fmt.Errorf(\"addAlbum: %v\", err)\n    }\n\n    return err\n}\n```\n\n- update album by ORM-like feature\n```go\nfunc updateAlbum(alb Album) error {\n    cmd := sqle.New().Update(\"album\").\n        SetModel(alb).\n        Where(\"id={id}\").Param(\"id\", alb.ID)\n\n    _, err := db.ExecBuilder(context.TODO(), cmd)\n    if err != nil {\n        return 0, fmt.Errorf(\"addAlbum: %v\", err)\n    }\n\n    return err\n}\n```\n\n### Delete\n- delete album by sql\n```go\nfunc deleteAlbumByID(id int64) error {\n    _, err := db.Exec(\"DELETE FROM album WHERE id = ?\", id)\n\n    return err\n}\n```\n- delete album by named sql statement\n```go\nfunc deleteAlbumByID(id int64) error {\n    _, err := db.ExecBuilder(context.TODO(), sqle.New().Delete(\"album\").Where(\"id = {id}\").\n        Param(\"id\",id))\n\n    return err\n}\n```\n\n### Transaction\nperform a set of operations within a transaction\n```go\nfunc deleteAlbums(ids []int64) error {\n\n    return db.Transaction(ctx, \u0026sql.TxOptions{}, func(ctx context.Context,tx *sqle.Tx) error {\n        var err error\n        for _, id := range ids {\n            _, err = tx.Exec(\"DELETE FROM album WHERE id=?\",id)\n            if err != nil {\n                return err\n            }\n        }\n    })\n}\n```\n\n\n## Table Rotation\nuse `shardid.ID` to enable rotate feature for a table based on option (NoRotate/MonthlyRotate/WeeklyRotate/DailyRotate)\n\n```go\ngen := shardid.New(shardid.WithMonthlyRotate())\nid := gen.Next()\n\nb := New().On(id) // call `On` to enable rotate feature, and setup an input variable \u003crotate\u003e\nb.Delete(\"orders\u003crotate\u003e\").Where().\n    If(true).And(\"order_id = {order_id}\").\n    If(false).And(\"member_id\").\n    Param(\"order_id\", \"order_123456\")\n\n\ndb.ExecBuilder(context.TODO(),b) // DELETE FROM `orders_20240220` WHERE order_id = ?\n```\nsee more [examples](sqlbuilder_test.go#L490)\n\n\n## Database Sharding\nuse `shardid.ID` to enable sharding feature for any sql\n```go\ngen := shardid.New(WithDatabase(10)) // 10 database instances\nid := gen.Next()\n\nb := New().On(id) // call `On` to setup an input variable named `rotate`, and enable rotation feature\nb.Delete(\"orders\u003crotate\u003e\").Where().\n    If(true).And(\"order_id = {order_id}\").\n    If(false).And(\"member_id\").\n    Param(\"order_id\", \"order_123456\")\n\n\ndb.On(id). // automatically select database based on `id.DatabaseID`\n ExecBuilder(context.TODO(),b) // DELETE FROM `orders` WHERE order_id = ?\n\n```\n\nsee more [examples](db_test.go#L49)\n\n## MapR Query\nSQLE uses `MapR[T]` queryer to connect and retrieve data from rotated tables and sharding databases. see more [examples](./queryer_mapr_test.go)\n\n## Migration\nSQLE discovers migrations from local file system or go embed file system. There are two objects here.\n- version directory\n\u003e it should be named as semver style. eg `0.0.1`/`1.0.2`. invalid naming will be ignored.\n- migration script file\n\u003e the file format is `{rank}_{description}.{suffix}`  eg `1_locale.sql`. the suffix can be filtered in `Discover`. eg `m.Discover(os.DirFS(\"./db\")), WithSuffix(\".postgres\"))`. `.sql` is default suffix filter.\nthe files should be organized as\n```\n├── db\n│   └── 0.0.1\n│       ├── 1_locale.sql\n│       ├── 2_member.sql\n│       ├── 3_order.sql\n│   └── 0.0.2\n│       ├── 1_add_times_orders.sql\n│       ├── 2_logs.sql\n```\nand database can be migrated in code\n```go\n    //go:embed db\n\tvar migrations embed.FS\n\n\tm := migrate.New(db)\n    // m.Discover(os.DirFS(\"./db\"))\n\tif err := m.Discover(migrations); err != nil {\n\t\tpanic(\" db: migrate \" + err.Error())\n\t}\n\n\terr = m.Init(context.TODO())\n\tif err != nil {\n\t\tpanic(\" db: migrate \" + err.Error())\n\t}\n\n\terr = m.Migrate(context.TODO())\n\tif err != nil {\n\t\tpanic(\" db: migrate \" + err.Error())\n\t}\n```\nsee more [examples](./migrate/migrator_test.go?L40)\n\nif a table has been rotated, and migration should be started with `/* rotate: monthly=20240201-20240401*/` as first line. so the migration is applied automatically on the table and all its rotated tables from 20240201 to 20240401.\n```sql\n/* rotate: monthly = 20240201 - 20240401 */\nCREATE TABLE IF NOT EXISTS monthly_logs\u003crotate\u003e (\n    id int NOT NULL,\n    msg varchar(50) NOT NULL,\n    PRIMARY KEY (id)\n);\n```\n\n`monthly_logs`, `monthly_logs_202402`, `monthly_logs_202403` and `monthly_logs_202404` will be migrated automatically.\n\nsee more [examples](./migrate/migrator_test.go?L360)\n\nif rotate is enabled for any table, rotate should be executed periodically in a cron job. so rotated tables will be created periodically.\n```\n├── db\n│   └── monthly\n│       ├── members.sql\n│   └── weekly\n│       ├── orders.sql\n│   └── daily\n│       ├── logs.sql\n```\nsee more [examples](./migrate/migrator_test.go?L581)\n\n## Security: SQL Injection\nSQLE uses the database/sql‘s argument placeholders to build parameterized SQL statement, which will automatically escape arguments to avoid SQL injection. eg if it is PostgreSQL, please apply [UsePostgres](use.go#L5) on SQLBuilder or change [DefaultSQLQuote](sqlbuilder.go?L16) and [DefaultSQLParameterize](sqlbuilder.go?L17) to update parameterization options.\n\n```go\nfunc UsePostgres(b *Builder) {\n\tb.Quote = \"`\"\n\tb.Parameterize = func(name string, index int) string {\n\t\treturn \"$\" + strconv.Itoa(index)\n\t}\n}\n```\n\n## Contributing\nContributions are welcome! If you're interested in contributing, please feel free to [contribute to SQLE](CONTRIBUTING.md)\n\n\n## License\n[MIT License](LICENSE)\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyaitoo%2Fsqle","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fyaitoo%2Fsqle","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyaitoo%2Fsqle/lists"}