{"id":13413674,"url":"https://github.com/golobby/orm","last_synced_at":"2025-03-14T19:32:57.923Z","repository":{"id":39003301,"uuid":"398478070","full_name":"golobby/orm","owner":"golobby","description":"A lightweight yet powerful, fast, customizable, type-safe object-relational mapper for the Go programming language.","archived":false,"fork":false,"pushed_at":"2023-08-30T14:54:40.000Z","size":402,"stargazers_count":157,"open_issues_count":6,"forks_count":5,"subscribers_count":4,"default_branch":"master","last_synced_at":"2024-07-31T20:52:37.836Z","etag":null,"topics":["database","generics","go","golang","object-relational-mapper","orm","orm-framework","query-builder","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/golobby.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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":"2021-08-21T05:50:38.000Z","updated_at":"2024-07-21T03:09:37.000Z","dependencies_parsed_at":"2024-02-06T01:48:46.150Z","dependency_job_id":null,"html_url":"https://github.com/golobby/orm","commit_stats":null,"previous_names":["golobby/sql"],"tags_count":10,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/golobby%2Form","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/golobby%2Form/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/golobby%2Form/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/golobby%2Form/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/golobby","download_url":"https://codeload.github.com/golobby/orm/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243635682,"owners_count":20322979,"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","generics","go","golang","object-relational-mapper","orm","orm-framework","query-builder","sql"],"created_at":"2024-07-30T20:01:46.105Z","updated_at":"2025-03-14T19:32:57.471Z","avatar_url":"https://github.com/golobby.png","language":"Go","readme":"[![GoDoc](https://godoc.org/github.com/golobby/orm/?status.svg)](https://godoc.org/github.com/golobby/orm)\n[![CI](https://github.com/golobby/orm/actions/workflows/ci.yml/badge.svg)](https://github.com/golobby/orm/actions/workflows/ci.yml)\n[![CodeQL](https://github.com/golobby/orm/actions/workflows/codeql-analysis.yml/badge.svg)](https://github.com/golobby/orm/actions/workflows/codeql-analysis.yml)\n[![Go Report Card](https://goreportcard.com/badge/github.com/golobby/orm)](https://goreportcard.com/report/github.com/golobby/orm)\n[![Coverage Status](https://coveralls.io/repos/github/golobby/orm/badge.svg?r=1)](https://coveralls.io/github/golobby/orm?branch=master)\n\n# Golobby ORM\n\nGoLobby ORM is a lightweight yet powerful, fast, customizable, type-safe object-relational mapper for the Go programming language.\n\n## Table Of Contents\n  * [Features](#features)\n    + [Introduction](#introduction)\n    + [Creating a new Entity](#creating-a-new-entity)\n      - [Conventions](#conventions)\n        * [Timestamps](#timestamps)\n        * [Column names](#column-names)\n        * [Primary Key](#primary-key)\n    + [Initializing ORM](#initializing-orm)\n    + [Fetching an entity from a database](#fetching-an-entity-from-a-database)\n    + [Saving entities or Insert/Update](#saving-entities-or-insert-update)\n    + [Using raw SQL](#using-raw-sql)\n    + [Deleting entities](#deleting-entities)\n    + [Relationships](#relationships)\n      - [HasMany](#hasmany)\n      - [HasOne](#hasone)\n      - [BelongsTo](#belongsto)\n      - [BelongsToMany](#belongstomany)\n      - [Saving with relation](#saving-with-relation)\n    + [Query Builder](#query-builder)\n      - [Finishers](#finishers)\n        * [All](#all)\n        * [Get](#get)\n        * [Update](#update)\n        * [Delete](#delete)\n      - [Select](#select)\n        * [Column names](#column-names-1)\n        * [Table](#table)\n        * [Where](#where)\n        * [Order By](#order-by)\n        * [Limit](#limit)\n        * [Offset](#offset)\n        * [First, Latest](#first-latest)\n      - [Update](#update)\n        * [Where](#where-1)\n        * [Table](#table-1)\n        * [Set](#set)\n      - [Delete](#delete)\n        * [Table](#table-2)\n        * [Where](#where-2)\n    + [Database Validations](#database-validations)\n  * [License](#license)\n\n## Introduction\nGoLobby ORM is an object-relational mapper (ORM) that makes it enjoyable to interact with your database. \nWhen using Golobby ORM, each database table has a corresponding \"Entity\" to interact with that table using elegant APIs.\n\n## Features\n- Elegant and easy-to-use APIs with the help of Generics.\n- Type-safety.\n- Using reflection at startup to be fast during runtime. \n- No code generation!\n- Query builder for various query types.\n- Binding query results to entities.\n- Supports different kinds of relationship/Association types:\n    - One to one\n    - One to Many\n    - Many to Many\n\n## Performance\nYou can run performance benchmark against `GORM` using\n```bash\nmake bench\n```\nhere are results from my laptop\n```\ngoos: darwin\ngoarch: arm64\npkg: github.com/golobby/orm/benchmark\nBenchmarkGolobby\nBenchmarkGolobby-8        235956              4992 ns/op            2192 B/op         66 allocs/op\nBenchmarkGorm\nBenchmarkGorm-8            54498             21308 ns/op            7208 B/op        147 allocs/op\nPASS\nok      github.com/golobby/orm/benchmark        3.118s\n```\n\n## Quick Start\n\nThe following example demonstrates how to use the GoLobby ORM.\n\n```go\npackage main\n\nimport \"github.com/golobby/orm\"\n\n// User entity\ntype User struct {\n  ID        int64\n  FirstName string\n  LastName  string\n  Email     string\n  orm.Timestamps\n}\n\n// It will be called by ORM to setup entity.\nfunc (u User) ConfigureEntity(e *orm.EntityConfigurator) {\n    // Specify related database table for the entity.\n    e.Table(\"users\")\n}\n\nfunc main() {\n  // Setup ORM\n  err := orm.Initialize(orm.ConnectionConfig{\n    // Name:          \"default\",  // Optional. Specify connection names if you have more than on database.\n    Driver:           \"sqlite3\",  // Database type. Currently supported sqlite3, mysql, mariadb, postgresql. \n    ConnectionString: \":memory:\", // Database DSN.\n    DatabaseValidations: true,    // Validates your database tables and each table schema\n  })\n  \n  if err != nil {\n\t  panic(err)\n  }\n  \n  // Find user by primary key (ID)\n  user, err := orm.Find[User](1)\n  \n  // Update entity\n  user.Email = \"jack@mail.com\"\n  \n  // Save entity\n  orm.Save(\u0026user)\n}\n```\n\n### Creating a new Entity\nLet's create a new `Entity` to represent `User` in our application.\n\n```go\npackage main\n\nimport \"github.com/golobby/orm\"\n\ntype User struct {\n  ID       int64\n  Name     string\n  LastName string\n  Email    string\n  orm.Timestamps\n}\n\nfunc (u User) ConfigureEntity(e *orm.EntityConfigurator) {\n    e.Table(\"users\").\n      Connection(\"default\") // You can omit connection name if you only have one.\n\t\n}\n```\nAs you see, our user entity is nothing else than a simple struct and two methods.\nEntities in GoLobby ORM are implementations of `Entity` interface, which defines two methods:\n- ConfigureEntity: configures table, fields, and also relations to other entities.\n#### Conventions\nWe have standard conventions and we encourage you to follow, but if you want to change them for any reason you can use `Field` method to customize how ORM\ninferres meta data from your `Entity`.\n\n##### Column names\nGoLobby ORM for each struct field(except slice, arrays, maps, and other nested structs) assumes a respective column named using snake case syntax.\nIf you want a custom column name, you should specify it in `ConfigureEntity` method using `Field()` method.\n```go\npackage main\n\ntype User struct {\n  Name string\n}\n\nfunc (u User) ConfigureEntity(e *orm.EntityConfigurator) {\n    e.Field(\"Name\").ColumnName(\"custom_name_for_column\")\n\n    e.Table(\"users\")\n}\n```\n##### Timestamps\nfor having `created_at`, `updated_at`, `deleted_at` timestamps in your entities you can embed `orm.Timestamps` struct in your entity,\n```go\ntype User struct {\n  ID       int64\n  Name     string\n  LastName string\n  Email    string\n  orm.Timestamps\n}\n\n```\nAlso, if you want custom names for them, you can do it like this.\n```go\ntype User struct {\n    ID       int64\n    Name     string\n    LastName string\n    Email    string\n    MyCreatedAt sql.NullTime\n    MyUpdatedAt sql.NullTime\n    MyDeletedAt sql.NullTime\n}\nfunc (u User) ConfigureEntity(e *orm.EntityConfigurator) {\n    e.Field(\"MyCreatedAt\").IsCreatedAt() // this will make ORM to use MyCreatedAt as created_at column\n    e.Field(\"MyUpdatedAt\").IsUpdatedAt() // this will make ORM to use MyUpdatedAt as created_at column\n    e.Field(\"MyDeletedAt\").IsDeletedAt() // this will make ORM to use MyDeletedAt as created_at column\n\n    e.Table(\"users\")\n}\n```\nAs always you use `Field` method for configuring how ORM behaves to your struct field.\n\n##### Primary Key\nGoLobby ORM assumes that each entity has a primary key named `id`; if you want a custom primary key called, you need to specify it in entity struct.\n```go\npackage main\n\ntype User struct {\n\tPK int64\n}\nfunc (u User) ConfigureEntity(e *orm.EntityConfigurator) {\n    e.Field(\"PK\").IsPrimaryKey() // this will make ORM use PK field as primary key.\n    e.Table(\"users\")\n}\n```\n\n### Initializing ORM\nAfter creating our entities, we need to initialize GoLobby ORM.\n```go\npackage main\n\nimport \"github.com/golobby/orm\"\n\nfunc main() {\n  orm.Initialize(orm.ConnectionConfig{\n    // Name:             \"default\", You should specify connection name if you have multiple connections\n    Driver:           \"sqlite3\",\n    ConnectionString: \":memory:\",\n  })\n}\n```\nAfter this step, we can start using ORM.\n### Fetching an entity from a database\nGoLobby ORM makes it trivial to fetch entities from a database using its primary key.\n```go\nuser, err := orm.Find[User](1)\n```\n`orm.Find` is a generic function that takes a generic parameter that specifies the type of `Entity` we want to query and its primary key value.\nYou can also use custom queries to get entities from the database.\n```go\n\nuser, err := orm.Query[User]().Where(\"id\", 1).First()\nuser, err := orm.Query[User]().WherePK(1).First()\n```\nGoLobby ORM contains a powerful query builder, which you can use to build `Select`, `Update`, and `Delete` queries, but if you want to write a raw SQL query, you can.\n```go\nusers, err := orm.QueryRaw[User](`SELECT * FROM users`)\n```\n\n### Saving entities or Insert/Update\nGoLobby ORM makes it easy to persist an `Entity` to the database using `Save` method, it's an UPSERT method, if the primary key field is not zero inside the entity\nit will go for an update query; otherwise, it goes for the insert.\n```go\n// this will insert entity into the table\nerr := orm.Save(\u0026User{Name: \"Amirreza\"}) // INSERT INTO users (name) VALUES (?) , \"Amirreza\"\n```\n```go\n// this will update entity with id = 1\norm.Save(\u0026User{ID: 1, Name: \"Amirreza2\"}) // UPDATE users SET name=? WHERE id=?, \"Amirreza2\", 1\n```\nAlso, you can do custom update queries using query builder or raw SQL again as well.\n```go\nres, err := orm.Query[User]().Where(\"id\", 1).Update(orm.KV{\"name\": \"amirreza2\"})\n```\n\n### Using raw SQL\n\n```go\n_, affected, err := orm.ExecRaw[User](`UPDATE users SET name=? WHERE id=?`, \"amirreza\", 1)\n```\n### Deleting entities  \nIt is also easy to delete entities from a database.\n```go\nerr := orm.Delete(user)\n```\nYou can also use query builder or raw SQL.\n```go\n_, affected, err := orm.Query[Post]().WherePK(1).Delete()\n\n_, affected, err := orm.Query[Post]().Where(\"id\", 1).Delete()\n\n```\n```go\n_, affected, err := orm.ExecRaw[Post](`DELETE FROM posts WHERE id=?`, 1)\n```\n### Relationships\nGoLobby ORM makes it easy to have entities that have relationships with each other. Configuring relations is using `ConfigureEntity` method, as you will see.\n#### HasMany\n```go\ntype Post struct {}\n\nfunc (p Post) ConfigureEntity(e *orm.EntityConfigurator) {\n    e.Table(\"posts\").HasMany(\u0026Comment{}, orm.HasManyConfig{})\n}\n```\nAs you can see, we are defining a `Post` entity that has a `HasMany` relation with `Comment`. You can configure how GoLobby ORM queries `HasMany` relation with `orm.HasManyConfig` object; by default, it will infer all fields for you.\nNow you can use this relationship anywhere in your code.\n```go\ncomments, err := orm.HasMany[Comment](post).All()\n```\n`HasMany` and other related functions in GoLobby ORM return `QueryBuilder`, and you can use them like other query builders and create even more\ncomplex queries for relationships. for example, you can start a query to get all comments of a post made today.\n```go\ntodayComments, err := orm.HasMany[Comment](post).Where(\"created_at\", \"CURDATE()\").All()\n```\n#### HasOne\nConfiguring a `HasOne` relation is like `HasMany`.\n```go\ntype Post struct {}\n\nfunc (p Post) ConfigureEntity(e *orm.EntityConfigurator) {\n    e.Table(\"posts\").HasOne(\u0026HeaderPicture{}, orm.HasOneConfig{})\n}\n```\nAs you can see, we are defining a `Post` entity that has a `HasOne` relation with `HeaderPicture`. You can configure how GoLobby ORM queries `HasOne` relation with `orm.HasOneConfig` object; by default, it will infer all fields for you.\nNow you can use this relationship anywhere in your code.\n```go\npicture, err := orm.HasOne[HeaderPicture](post)\n```\n`HasOne` also returns a query builder, and you can create more complex queries for relations.\n#### BelongsTo\n```go\ntype Comment struct {}\n\nfunc (c Comment) ConfigureEntity(e *orm.EntityConfigurator) {\n    e.Table(\"comments\").BelongsTo(\u0026Post{}, orm.BelongsToConfig{})\n}\n```\nAs you can see, we are defining a `Comment` entity that has a `BelongsTo` relation with `Post` that we saw earlier. You can configure how GoLobby ORM queries `BelongsTo` relation with `orm.BelongsToConfig` object; by default, it will infer all fields for you.\nNow you can use this relationship anywhere in your code.\n```go\npost, err := orm.BelongsTo[Post](comment).First()\n```\n#### BelongsToMany\n```go\ntype Post struct {}\n\nfunc (p Post) ConfigureEntity(e *orm.EntityConfigurator) {\n    e.Table(\"posts\").BelongsToMany(\u0026Category{}, orm.BelongsToManyConfig{IntermediateTable: \"post_categories\"})\n}\n\ntype Category struct{}\n\nfunc(c Category) ConfigureEntity(r *orm.EntityConfigurator) {\n    e.Table(\"categories\").BelongsToMany(\u0026Post{}, orm.BelongsToManyConfig{IntermediateTable: \"post_categories\"})\n}\n\n```\nWe are defining a `Post` entity and a `Category` entity with a `many2many` relationship; as you can see, we must configure the IntermediateTable name, which GoLobby ORM cannot infer.\nNow you can use this relationship anywhere in your code.\n```go\ncategories, err := orm.BelongsToMany[Category](post).All()\n```\n#### Saving with relation\nYou may need to save an entity that has some kind of relationship with another entity; in that case, you can use `Add` method.\n```go\norm.Add(post, comments...) // inserts all comments passed in and also sets all post_id to the primary key of the given post.\norm.Add(post, categories...) // inserts all categories and also insert intermediate post_categories records.\n```\n\n### Query Builder\nGoLobby ORM contains a powerful query builder to help you build complex queries with ease. QueryBuilder is accessible from `orm.Query[Entity]` method\nwhich will create a new query builder for you with given type parameter.\nQuery builder can build `SELECT`,`UPDATE`,`DELETE` queries for you.\n\n#### Finishers\nFinishers are methods on QueryBuilder that will some how touch database, so use them with caution.\n##### All\nAll will generate a `SELECT` query from QueryBuilder, execute it on database and return results in a slice of OUTPUT. It's useful for queries that have multiple results.\n```go\nposts, err := orm.Query[Post]().All() \n```\n##### Get\nGet will generate a `SELECT` query from QueryBuilder, execute it on database and return results in an instance of type parameter `OUTPUT`. It's useful for when you know your query has single result.\n```go\npost, err := orm.Query[Post]().First().Get()\n```\n##### Update\nUpdate will generate an `UPDATE` query from QueryBuilder and executes it, returns rows affected by query and any possible error.\n```go\nrowsAffected, err := orm.Query[Post]().WherePK(1).Set(\"body\", \"body jadid\").Update()\n```\n##### Delete\nDelete will generate a `DELETE` query from QueryBuilder and executes it, returns rows affected by query and any possible error.\n```go\nrowsAffected, err := orm.Query[Post]().WherePK(1).Delete()\n```\n#### Select\nLet's start with `Select` queries.\nEach `Select` query consists of following:\n```sql\nSELECT [column names] FROM [table name] WHERE [cond1 AND/OR cond2 AND/OR ...] ORDER BY [column] [ASC/DESC] LIMIT [N] OFFSET [N] GROUP BY [col]\n```\nQuery builder has methods for constructing each part, of course not all of these parts are necessary.\n##### Column names\nfor setting column names to select use `Select` method as following:\n```go\norm.Query[Post]().Select(\"id\", \"title\")\n```\n##### Table\nfor setting table name for select use `Table` method as following:\n```go\norm.Query[Post]().Table(\"users\")\n```\n##### Where\nfor adding where conditions based on what kind of where you want you can use any of following:\n```go\norm.Query[Post]().Where(\"name\", \"amirreza\") // Equal mode: WHERE name = ?, [\"amirreza\"]\norm.Query[Post]().Where(\"age\", \"\u003c\", 19) // Operator mode: WHERE age \u003c ?, [19]\norm.Query[Post]().WhereIn(\"id\", 1,2,3,4,5) // WhereIn: WHERE id IN (?,?,?,?,?), [1,2,3,4,5]\n```\nYou can also chain these together.\n```go\norm.Query[Post]().\n\tWhere(\"name\", \"amirreza\").\n\tAndWhere(\"age\", \"\u003c\", 10).\n\tOrWhere(\"id\", \"!=\", 1)\n    // WHERE name = ? AND age \u003c ? OR id != ?, [\"amirreza\", 10, 1]\n```\n##### Order By\nYou can set order by of query using `OrderBy` as following.\n```go\norm.Query[Post]().OrderBy(\"id\", orm.ASC) // ORDER BY id ASC\norm.Query[Post]().OrderBy(\"id\", orm.DESC) // ORDER BY id DESC\n```\n\n##### Limit\nYou can set limit setting of query using `Limit` as following\n```go\norm.Query[Post]().Limit1(1) // LIMIT 1\n```\n\n##### Offset\nYou can set limit setting of query using `Offset` as following\n```go\norm.Query[Post]().Offset(1) // OFFSET 1\n```\n\n##### First, Latest\nYou can use `First`, `Latest` method which are also executers of query as you already seen to get first or latest record.\n```go\norm.Query[Post]().First() // SELECT * FROM posts ORDER BY id ASC LIMIT 1\norm.Query[Post]().Latest() // SELECT * FROM posts ORDER BY id DESC LIMIT 1\n```\n#### Update\nEach `Update` query consists of following:\n```sql\nUPDATE [table name] SET [col=val] WHERE [cond1 AND/OR cond2 AND/OR ...]\n```\n##### Where\nJust like select where stuff, same code.\n\n##### Table\nSame as select.\n\n##### Set\nYou can use `Set` method to set value.\n```go\norm.Query[Message]().\n  Where(\"id\", 1).\n  Set(\"read\", true, \"seen\", true).\n  Update() // UPDATE posts SET read=?, seen=? WHERE id = ?, [true, true, 1]\n```\n\n#### Delete\nEach `Delete` query consists of following:\n```sql\nDELETE FROM [table name] WHERE [cond1 AND/OR cond2 AND/OR ...]\n```\n##### Table\nSame as Select and Update.\n##### Where\nSame as Select and Update.\n### Database Validations\nGolobby ORM can validate your database state and compare it to your entities and if your database and code are not in sync give you error.\nCurrently there are two database validations possible:\n1. Validate all necessary tables exists.\n2. Validate all tables contain necessary columns.\nYou can enable database validations feature by enabling `DatabaseValidations` flag in your ConnectionConfig.\n```go\nreturn orm.SetupConnections(orm.ConnectionConfig{\n    Name:                    \"default\",\n    DB:                      db,\n    Dialect:                 orm.Dialects.SQLite3,\n    Entities:                []orm.Entity{\u0026Post{}, \u0026Comment{}, \u0026Category{}, \u0026HeaderPicture{}},\n    DatabaseValidations: true,\n  })\n```\n## License\nGoLobby ORM is released under the [MIT License](http://opensource.org/licenses/mit-license.php).\n","funding_links":[],"categories":["Go","ORM"],"sub_categories":["HTTP客户端","HTTP Clients"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgolobby%2Form","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgolobby%2Form","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgolobby%2Form/lists"}