{"id":13412173,"url":"https://github.com/go-ozzo/ozzo-dbx","last_synced_at":"2025-06-11T04:16:46.340Z","repository":{"id":2888421,"uuid":"47791533","full_name":"go-ozzo/ozzo-dbx","owner":"go-ozzo","description":"A Go (golang) package that enhances the standard database/sql package by providing powerful data retrieval methods as well as DB-agnostic query building capabilities.","archived":false,"fork":false,"pushed_at":"2023-05-01T13:39:42.000Z","size":210,"stargazers_count":636,"open_issues_count":41,"forks_count":90,"subscribers_count":30,"default_branch":"master","last_synced_at":"2024-10-25T04:09:56.834Z","etag":null,"topics":["database","go","golang","ozzo"],"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/go-ozzo.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}},"created_at":"2015-12-10T22:39:26.000Z","updated_at":"2024-10-23T15:40:16.000Z","dependencies_parsed_at":"2023-07-05T20:02:29.221Z","dependency_job_id":null,"html_url":"https://github.com/go-ozzo/ozzo-dbx","commit_stats":{"total_commits":99,"total_committers":8,"mean_commits":12.375,"dds":"0.11111111111111116","last_synced_commit":"4d1628e5e24835bb0fd34eeafe480387b836fa23"},"previous_names":[],"tags_count":21,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/go-ozzo%2Fozzo-dbx","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/go-ozzo%2Fozzo-dbx/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/go-ozzo%2Fozzo-dbx/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/go-ozzo%2Fozzo-dbx/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/go-ozzo","download_url":"https://codeload.github.com/go-ozzo/ozzo-dbx/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/go-ozzo%2Fozzo-dbx/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":259197980,"owners_count":22820156,"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","go","golang","ozzo"],"created_at":"2024-07-30T20:01:21.789Z","updated_at":"2025-06-11T04:16:46.315Z","avatar_url":"https://github.com/go-ozzo.png","language":"Go","funding_links":[],"categories":["开源类库","Database","SQL Builders","Open source library","Go","数据库  `go语言实现的数据库`","\u003cspan id=\"数据库-database\"\u003e数据库 Database\u003c/span\u003e","Data Integration Frameworks","数据库","Uncategorized","Generators"],"sub_categories":["数据库","SQL Query Builders","Advanced Console UIs","Database","SQL 查询语句构建库","\u003cspan id=\"高级控制台用户界面-advanced-console-uis\"\u003e高级控制台用户界面 Advanced Console UIs\u003c/span\u003e","SQL查询生成器"],"readme":"# ozzo-dbx\n\n[![GoDoc](https://godoc.org/github.com/go-ozzo/ozzo-dbx?status.png)](http://godoc.org/github.com/go-ozzo/ozzo-dbx)\n[![Build Status](https://travis-ci.org/go-ozzo/ozzo-dbx.svg?branch=master)](https://travis-ci.org/go-ozzo/ozzo-dbx)\n[![Coverage Status](https://coveralls.io/repos/github/go-ozzo/ozzo-dbx/badge.svg?branch=master)](https://coveralls.io/github/go-ozzo/ozzo-dbx?branch=master)\n[![Go Report](https://goreportcard.com/badge/github.com/go-ozzo/ozzo-dbx)](https://goreportcard.com/report/github.com/go-ozzo/ozzo-dbx)\n\n## Summary\n\n- [Description](#description)\n- [Requirements](#requirements)\n- [Installation](#installation)\n- [Supported Databases](#supported-databases)\n- [Getting Started](#getting-started)\n- [Connecting to Database](#connecting-to-database)\n- [Executing Queries](#executing-queries)\n- [Binding Parameters](#binding-parameters)\n- [Building Queries](#building-queries)\n\t- [Building SELECT Queries](#building-select-queries)\n\t- [Building Query Conditions](#building-query-conditions)\n\t- [Building Data Manipulation Queries](#building-data-manipulation-queries)\n\t- [Building Schema Manipulation Queries](#building-schema-manipulation-queries)\n- [CRUD Operations](#crud-operations)\n\t- [Create](#create)\n\t- [Read](#read)\n\t- [Update](#update)\n\t- [Delete](#delete)\n\t- [Null Handling](#null-handling)\n- [Quoting Table and Column Names](#quoting-table-and-column-names)\n- [Using Transactions](#using-transactions)\n- [Logging Executed SQL Statements](#logging-executed-sql-statements)\n- [Supporting New Databases](#supporting-new-databases)\n\n## Other Languages\n\n[Русский](/docs/README-ru.md)\n\n## Description\n\nozzo-dbx is a Go package that enhances the standard `database/sql` package by providing powerful data retrieval methods\nas well as DB-agnostic query building capabilities. ozzo-dbx is not an ORM. It has the following features:\n\n* Populating data into structs and NullString maps\n* Named parameter binding\n* DB-agnostic query building methods, including SELECT queries, data manipulation queries, and schema manipulation queries\n* Inserting, updating, and deleting model structs\n* Powerful query condition building\n* Open architecture allowing addition of new database support or customization of existing support\n* Logging executed SQL statements\n* Supporting major relational databases\n\nFor an example on how this library is used in an application, please refer to [go-rest-api](https://github.com/qiangxue/go-rest-api) which is a starter kit for building RESTful APIs in Go.\n\n## Requirements\n\nGo 1.13 or above.\n\n## Installation\n\nRun the following command to install the package:\n\n```\ngo get github.com/go-ozzo/ozzo-dbx\n```\n\nIn addition, install the specific DB driver package for the kind of database to be used. Please refer to\n[SQL database drivers](https://github.com/golang/go/wiki/SQLDrivers) for a complete list. For example, if you are\nusing MySQL, you may install the following package:\n\n```\ngo get github.com/go-sql-driver/mysql\n```\n\nand import it in your main code like the following:\n\n```go\nimport _ \"github.com/go-sql-driver/mysql\"\n```\n\n## Supported Databases\n\nThe following databases are fully supported out of box:\n\n* SQLite\n* MySQL\n* PostgreSQL\n* MS SQL Server (2012 or above)\n* Oracle\n\nFor other databases, the query building feature may not work as expected. You can create a custom builder to\nsolve the problem. Please see the last section for more details.\n\n## Getting Started\n\nThe following code snippet shows how you can use this package in order to access data from a MySQL database.\n\n```go\nimport (\n\t\"fmt\"\n\t\"github.com/go-ozzo/ozzo-dbx\"\n\t_ \"github.com/go-sql-driver/mysql\"\n)\n\nfunc main() {\n\tdb, _ := dbx.Open(\"mysql\", \"user:pass@/example\")\n\n\t// create a new query\n\tq := db.NewQuery(\"SELECT id, name FROM users LIMIT 10\")\n\n\t// fetch all rows into a struct array\n\tvar users []struct {\n\t\tID, Name string\n\t}\n\terr := q.All(\u0026users)\n\n\t// fetch a single row into a struct\n\tvar user struct {\n\t\tID, Name string\n\t}\n\terr = q.One(\u0026user)\n\n\t// fetch a single row into a string map\n\tdata := dbx.NullStringMap{}\n\terr = q.One(data)\n\n\t// fetch row by row\n\trows2, _ := q.Rows()\n\tfor rows2.Next() {\n\t\t_ = rows2.ScanStruct(\u0026user)\n\t\t// rows.ScanMap(data)\n\t\t// rows.Scan(\u0026id, \u0026name)\n\t}\n}\n```\n\nAnd the following example shows how to use the query building capability of this package.\n\n```go\nimport (\n\t\"fmt\"\n\t\"github.com/go-ozzo/ozzo-dbx\"\n\t_ \"github.com/go-sql-driver/mysql\"\n)\n\nfunc main() {\n\tdb, _ := dbx.Open(\"mysql\", \"user:pass@/example\")\n\n\t// build a SELECT query\n\t//   SELECT `id`, `name` FROM `users` WHERE `name` LIKE '%Charles%' ORDER BY `id`\n\tq := db.Select(\"id\", \"name\").\n\t\tFrom(\"users\").\n\t\tWhere(dbx.Like(\"name\", \"Charles\")).\n\t\tOrderBy(\"id\")\n\n\t// fetch all rows into a struct array\n\tvar users []struct {\n\t\tID, Name string\n\t}\n\terr := q.All(\u0026users)\n\n\t// build an INSERT query\n\t//   INSERT INTO `users` (`name`) VALUES ('James')\n\terr = db.Insert(\"users\", dbx.Params{\n\t\t\"name\": \"James\",\n\t}).Execute()\n}\n```\n\n## Connecting to Database\n\nTo connect to a database, call `dbx.Open()` in the same way as you would do with the `Open()` method in `database/sql`.\n\n```go\ndb, err := dbx.Open(\"mysql\", \"user:pass@hostname/db_name\")\n```\n\nThe method returns a `dbx.DB` instance which can be used to create and execute DB queries. Note that the method \ndoes not really establish a connection until a query is made using the returned `dbx.DB` instance. It also\ndoes not check the correctness of the data source name either. Call `dbx.MustOpen()` to make sure the data \nsource name is correct.\n\n## Executing Queries\n\nTo execute a SQL statement, first create a `dbx.Query` instance by calling `DB.NewQuery()` with the SQL statement\nto be executed. And then call `Query.Execute()` to execute the query if the query is not meant to retrieving data.\nFor example,\n\n```go\nq := db.NewQuery(\"UPDATE users SET status=1 WHERE id=100\")\nresult, err := q.Execute()\n```\n\nIf the SQL statement does retrieve data (e.g. a SELECT statement), one of the following methods should be called, \nwhich will execute the query and populate the result into the specified variable(s).\n\n* `Query.All()`: populate all rows of the result into a slice of structs or `NullString` maps.\n* `Query.One()`: populate the first row of the result into a struct or a `NullString` map.\n* `Query.Column()`: populate the first column of the result into a slice.\n* `Query.Row()`: populate the first row of the result into a list of variables, one for each returning column.\n* `Query.Rows()`: returns a `dbx.Rows` instance to allow retrieving data row by row.\n\nFor example,\n\n```go\ntype User struct {\n\tID   int\n\tName string\n}\n\nvar (\n\tusers []User\n\tuser User\n\n\trow dbx.NullStringMap\n\n\tid   int\n\tname string\n\n\terr error\n)\n\nq := db.NewQuery(\"SELECT id, name FROM users LIMIT 10\")\n\n// populate all rows into a User slice\nerr = q.All(\u0026users)\nfmt.Println(users[0].ID, users[0].Name)\n\n// populate the first row into a User struct\nerr = q.One(\u0026user)\nfmt.Println(user.ID, user.Name)\n\n// populate the first row into a NullString map\nerr = q.One(\u0026row)\nfmt.Println(row[\"id\"], row[\"name\"])\n\nvar ids []int\nerr = q.Column(\u0026ids)\nfmt.Println(ids)\n\n// populate the first row into id and name\nerr = q.Row(\u0026id, \u0026name)\n\n// populate data row by row\nrows, _ := q.Rows()\nfor rows.Next() {\n\t_ = rows.ScanMap(\u0026row)\n}\n```\n\nWhen populating a struct, the following rules are used to determine which columns should go into which struct fields:\n\n* Only exported struct fields can be populated.\n* A field receives data if its name is mapped to a column according to the field mapping function `Query.FieldMapper`.\n  The default field mapping function separates words in a field name by underscores and turns them into lower case.\n  For example, a field name `FirstName` will be mapped to the column name `first_name`, and `MyID` to `my_id`.\n* If a field has a `db` tag, the tag value will be used as the corresponding column name. If the `db` tag is a dash `-`,\n  it means the field should NOT be populated.\n* For anonymous fields that are of struct type, they will be expanded and their component fields will be populated\n  according to the rules described above.\n* For named fields that are of struct type, they will also be expanded. But their component fields will be prefixed\n  with the struct names when being populated.\n  \nAn exception to the above struct expansion is that when a struct type implements `sql.Scanner` or when it is `time.Time`.\nIn this case, the field will be populated as a whole by the DB driver. Also, if a field is a pointer to some type,\nthe field will be allocated memory and populated with the query result if it is not null. \n\nThe following example shows how fields are populated according to the rules above:\n\n```go\ntype User struct {\n\tid     int\n\tType   int `db:\"-\"`\n\tMyName string `db:\"name\"`\n\tProfile\n\tAddress Address `db:\"addr\"`\n}\n\ntype Profile struct {\n\tAge int\n}\n\ntype Address struct {\n\tCity string\n}\n```\n\n* `User.id`: not populated because the field is not exported;\n* `User.Type`: not populated because the `db` tag is `-`;\n* `User.MyName`: to be populated from the `name` column, according to the `db` tag;\n* `Profile.Age`: to be populated from the `age` column, since `Profile` is an anonymous field;\n* `Address.City`: to be populated from the `addr.city` column, since `Address` is a named field of struct type\n  and its fields will be prefixed with `addr.` according to the `db` tag.\n\nNote that if a column in the result does not have a corresponding struct field, it will be ignored. Similarly,\nif a struct field does not have a corresponding column in the result, it will not be populated.\n\n## Binding Parameters\n\nA SQL statement is usually parameterized with dynamic values. For example, you may want to select the user record\naccording to the user ID received from the client. Parameter binding should be used in this case, and it is almost\nalways preferred to prevent from SQL injection attacks. Unlike `database/sql` which does anonymous parameter binding, \n`ozzo-dbx` uses named parameter binding. *Anonymous parameter binding is not supported*, as it will mess up with named\nparameters. For example,\n\n```go\nq := db.NewQuery(\"SELECT id, name FROM users WHERE id={:id}\")\nq.Bind(dbx.Params{\"id\": 100})\nerr := q.One(\u0026user)\n```\n\nThe above example will select the user record whose `id` is 100. The method `Query.Bind()` binds a set\nof named parameters to a SQL statement which contains parameter placeholders in the format of `{:ParamName}`.\n\nIf a SQL statement needs to be executed multiple times with different parameter values, it may be prepared\nto improve the performance. For example,\n\n```go\nq := db.NewQuery(\"SELECT id, name FROM users WHERE id={:id}\")\nq.Prepare()\ndefer q.Close()\n\nq.Bind(dbx.Params{\"id\": 100})\nerr := q.One(\u0026user)\n\nq.Bind(dbx.Params{\"id\": 200})\nerr = q.One(\u0026user)\n\n// ...\n```\n\n\n## Cancelable Queries\n\nQueries are cancelable when they are used with `context.Context`. In particular, by calling `Query.WithContext()` you\ncan associate a context with a query and use the context to cancel the query while it is running. For example,\n\n```go\nq := db.NewQuery(\"SELECT id, name FROM users\")\nerr := q.WithContext(ctx).All(\u0026users)\n```\n\n\n## Building Queries\n\nInstead of writing plain SQLs, `ozzo-dbx` allows you to build SQLs programmatically, which often leads to cleaner,\nmore secure, and DB-agnostic code. You can build three types of queries: the SELECT queries, the data manipulation\nqueries, and the schema manipulation queries.\n\n### Building SELECT Queries\n\nBuilding a SELECT query starts by calling `DB.Select()`. You can build different clauses of a SELECT query using\nthe corresponding query building methods. For example,\n\n```go\ndb, _ := dbx.Open(\"mysql\", \"user:pass@/example\")\nerr := db.Select(\"id\", \"name\").\n\tFrom(\"users\").\n\tWhere(dbx.HashExp{\"id\": 100}).\n\tOne(\u0026user)\n```\n\nThe above code will generate and execute the following SQL statement:\n\n```sql\nSELECT `id`, `name` FROM `users` WHERE `id`={:p0} \n```\n\nNotice how the table and column names are properly quoted according to the currently using database type.\nAnd parameter binding is used to populate the value of `p0` in the `WHERE` clause.\n\nEvery SQL keyword has a corresponding query building method. For example, `SELECT` corresponds to `Select()`,\n`FROM` corresponds to `From()`, `WHERE` corresponds to `Where()`, and so on. You can chain these method calls\ntogether, just like you would do when writing a plain SQL. Each of these methods returns the query instance\n(of type `dbx.SelectQuery`) that is being built. Once you finish building a query, you may call methods such as\n`One()`, `All()` to execute the query and populate data into variables. You may also explicitly call `Build()`\nto build the query and turn it into a `dbx.Query` instance which may allow you to get the SQL statement and do\nother interesting work.\n\n\n### Building Query Conditions\n\n`ozzo-dbx` supports very flexible and powerful query condition building which can be used to build SQL clauses\nsuch as `WHERE`, `HAVING`, etc. For example,\n\n```go\n// id=100\ndbx.NewExp(\"id={:id}\", dbx.Params{\"id\": 100})\n\n// id=100 AND status=1\ndbx.HashExp{\"id\": 100, \"status\": 1}\n\n// status=1 OR age\u003e30\ndbx.Or(dbx.HashExp{\"status\": 1}, dbx.NewExp(\"age\u003e30\"))\n\n// name LIKE '%admin%' AND name LIKE '%example%'\ndbx.Like(\"name\", \"admin\", \"example\")\n```\n\nWhen building a query condition expression, its parameter values will be populated using parameter binding, which\nprevents SQL injection from happening. Also if an expression involves column names, they will be properly quoted.\nThe following condition building functions are available:\n\n* `dbx.NewExp()`: creating a condition using the given expression string and binding parameters. For example,\n`dbx.NewExp(\"id={:id}\", dbx.Params{\"id\":100})` would create the expression `id=100`.\n* `dbx.HashExp`: a map type that represents name-value pairs concatenated by `AND` operators. For example,\n`dbx.HashExp{\"id\":100, \"status\":1}` would create `id=100 AND status=1`.\n* `dbx.Not()`: creating a `NOT` expression by prepending `NOT` to the given expression.\n* `dbx.And()`: creating an `AND` expression by concatenating the given expressions with the `AND` operators.\n* `dbx.Or()`: creating an `OR` expression by concatenating the given expressions with the `OR` operators.\n* `dbx.In()`: creating an `IN` expression for the specified column and the range of values.\nFor example, `dbx.In(\"age\", 30, 40, 50)` would create the expression `age IN (30, 40, 50)`.\nNote that if the value range is empty, it will generate an expression representing a false value.\n* `dbx.NotIn()`: creating an `NOT IN` expression. This is very similar to `dbx.In()`. \n* `dbx.Like()`: creating a `LIKE` expression for the specified column and the range of values. For example, \n`dbx.Like(\"title\", \"golang\", \"framework\")` would create the expression `title LIKE \"%golang%\" AND title LIKE \"%framework%\"`.\nYou can further customize a LIKE expression by calling `Escape()` and/or `Match()` functions of the resulting expression.\nNote that if the value range is empty, it will generate an empty expression. \n* `dbx.NotLike()`: creating a `NOT LIKE` expression. This is very similar to `dbx.Like()`.\n* `dbx.OrLike()`: creating a `LIKE` expression but concatenating different `LIKE` sub-expressions using `OR` instead of `AND`.\n* `dbx.OrNotLike()`: creating a `NOT LIKE` expression and concatenating different `NOT LIKE` sub-expressions using `OR` instead of `AND`.\n* `dbx.Exists()`: creating an `EXISTS` expression by prepending `EXISTS` to the given expression.\n* `dbx.NotExists()`: creating a `NOT EXISTS` expression by prepending `NOT EXISTS` to the given expression.\n* `dbx.Between()`: creating a `BETWEEN` expression. For example, `dbx.Between(\"age\", 30, 40)` would create the \nexpression `age BETWEEN 30 AND 40`.\n* `dbx.NotBetween()`: creating a `NOT BETWEEN` expression. For example\n\nYou may also create other convenient functions to help building query conditions, as long as the functions return\nan object implementing the `dbx.Expression` interface.\n \n\n### Building Data Manipulation Queries\n\nData manipulation queries are those changing the data in the database, such as INSERT, UPDATE, DELETE statements.\nSuch queries can be built by calling the corresponding methods of `DB`. For example,\n\n```go\ndb, _ := dbx.Open(\"mysql\", \"user:pass@/example\")\n\n// INSERT INTO `users` (`name`, `email`) VALUES ({:p0}, {:p1})\nerr := db.Insert(\"users\", dbx.Params{\n\t\"name\": \"James\",\n\t\"email\": \"james@example.com\",\n}).Execute()\n\n// UPDATE `users` SET `status`={:p0} WHERE `id`={:p1}\nerr = db.Update(\"users\", dbx.Params{\"status\": 1}, dbx.HashExp{\"id\": 100}).Execute()\n\n// DELETE FROM `users` WHERE `status`={:p0}\nerr = db.Delete(\"users\", dbx.HashExp{\"status\": 2}).Execute()\n```\n\nWhen building data manipulation queries, remember to call `Execute()` at the end to execute the queries.\n\n### Building Schema Manipulation Queries\n\nSchema manipulation queries are those changing the database schema, such as creating a new table, adding a new column.\nThese queries can be built by calling the corresponding methods of `DB`. For example,\n\n```go\ndb, _ := dbx.Open(\"mysql\", \"user:pass@/example\")\n\n// CREATE TABLE `users` (`id` int primary key, `name` varchar(255))\nq := db.CreateTable(\"users\", map[string]string{\n\t\"id\": \"int primary key\",\n\t\"name\": \"varchar(255)\",\n})\nerr := q.Execute()\n```\n\n## CRUD Operations\n\nAlthough ozzo-dbx is not an ORM, it does provide a very convenient way to do typical CRUD (Create, Read, Update, Delete)\noperations without the need of writing plain SQL statements.\n\nTo use the CRUD feature, first define a struct type for a table. By default, a struct is associated with a table\nwhose name is the snake case version of the struct type name. For example, a struct named `MyCustomer`\ncorresponds to the table name `my_customer`. You may explicitly specify the table name for a struct by implementing\nthe `dbx.TableModel` interface. For example,\n\n```go\ntype MyCustomer struct{}\n\nfunc (c MyCustomer) TableName() string {\n\treturn \"customer\"\n}\n```\n\nNote that the `TableName` method should be defined with a value receiver instead of a pointer receiver. \n\nIf the struct has a field named `ID` or `Id`, by default the field will be treated as the primary key field.\nIf you want to use a different field as the primary key, tag it with `db:\"pk\"`. You may tag multiple fields\nfor composite primary keys. Note that if you also want to explicitly specify the column name for a primary key field,\nyou should use the tag format `db:\"pk,col_name\"`.\n\nYou can give a common prefix or suffix to your table names by defining your own table name mapping via \n`DB.TableMapFunc`. For example, the following code prefixes `tbl_` to all table names. \n\n```go\ndb.TableMapper = func(a interface{}) string {\n    return \"tbl_\" + GetTableName(a)\n}\n```\n\n### Create\n\nTo create (insert) a new row using a model, call the `ModelQuery.Insert()` method. For example,\n\n```go\ntype Customer struct {\n\tID     int\n\tName   string\n\tEmail  string\n\tStatus int\n}\n\ndb, _ := dbx.Open(\"mysql\", \"user:pass@/example\")\n\ncustomer := Customer{\n\tName: \"example\",\n\tEmail: \"test@example.com\",\n}\n// INSERT INTO customer (name, email, status) VALUES ('example', 'test@example.com', 0)\nerr := db.Model(\u0026customer).Insert()\n```\n\nThis will insert a row using the values from *all* public fields (except the primary key field if it is empty) in the struct.\nIf a primary key field is zero (a integer zero or a nil pointer), it is assumed to be auto-incremental and \nwill be automatically filled with the last insertion ID after a successful insertion.\n\nYou can explicitly specify the fields that should be inserted by passing the list of the field names to the `Insert()` method.\nYou can also exclude certain fields from being inserted by calling `Exclude()` before calling `Insert()`. For example,\n\n```go\ndb, _ := dbx.Open(\"mysql\", \"user:pass@/example\")\n\n// insert only Name and Email fields\nerr := db.Model(\u0026customer).Insert(\"Name\", \"Email\")\n// insert all public fields except Status\nerr = db.Model(\u0026customer).Exclude(\"Status\").Insert()\n// insert only Name\nerr = db.Model(\u0026customer).Exclude(\"Status\").Insert(\"Name\", \"Status\")\n```\n\n### Read\n\nTo read a model by a given primary key value, call `SelectQuery.Model()`.\n\n```go\ndb, _ := dbx.Open(\"mysql\", \"user:pass@/example\")\n\nvar customer Customer\n// SELECT * FROM customer WHERE id=100\nerr := db.Select().Model(100, \u0026customer)\n\n// SELECT name, email FROM customer WHERE status=1 AND id=100\nerr = db.Select(\"name\", \"email\").Where(dbx.HashExp{\"status\": 1}).Model(100, \u0026customer)\n```\n\nNote that `SelectQuery.Model()` does not support composite primary keys. You should use `SelectQuery.One()` in this case.\nFor example,\n\n```go\ndb, _ := dbx.Open(\"mysql\", \"user:pass@/example\")\n\nvar orderItem OrderItem\n\n// SELECT * FROM order_item WHERE order_id=100 AND item_id=20\nerr := db.Select().Where(dbx.HashExp{\"order_id\": 100, \"item_id\": 20}).One(\u0026orderItem)\n```\n\nIn the above queries, we do not call `From()` to specify which table to select data from. This is because the select\nquery automatically sets the table according to the model struct being populated. If the struct implements `TableModel`,\nthe value returned by its `TableName()` method will be used as the table name. Otherwise, the snake case version\nof the struct type name will be the table name.\n\nYou may also call `SelectQuery.All()` to read a list of model structs. Similarly, you do not need to call `From()`\nif the table name can be inferred from the model structs.\n\n\n### Update\n\nTo update a model, call the `ModelQuery.Update()` method. Like `Insert()`, by default, the `Update()` method will\nupdate *all* public fields except primary key fields of the model. You can explicitly specify which fields can\nbe updated and which cannot in the same way as described for the `Insert()` method. For example,\n\n```go\ndb, _ := dbx.Open(\"mysql\", \"user:pass@/example\")\n\n// update all public fields of customer\nerr := db.Model(\u0026customer).Update()\n// update only Status\nerr = db.Model(\u0026customer).Update(\"Status\")\n// update all public fields except Status\nerr = db.Model(\u0026customer).Exclude(\"Status\").Update()\n```\n\nNote that the `Update()` method assumes that the primary keys are immutable. It uses the primary key value of the model\nto look for the row that should be updated. An error will be returned if a model does not have a primary key.\n\n\n### Delete\n\nTo delete a model, call the `ModelQuery.Delete()` method. The method deletes the row using the primary key value\nspecified by the model. If the model does not have a primary key, an error will be returned. For example,\n\n```go\ndb, _ := dbx.Open(\"mysql\", \"user:pass@/example\")\n\nerr := db.Model(\u0026customer).Delete()\n```\n\n### Null Handling\n\nTo represent a nullable database value, you can use a pointer type. If the pointer is nil, it means the corresponding \ndatabase value is null. \n\nAnother option to represent a database null is to use `sql.NullXyz` types. For example, if a string column is nullable,\nyou may use `sql.NullString`. The `NullString.Valid` field indicates whether the value is a null or not, and \n`NullString.String` returns the string value when it is not null. Because `sql.NulLXyz` types do not handle JSON \nmarshalling, you may use the [null package](https://github.com/guregu/null), instead. \n\nBelow is an example of handling nulls:\n\n```go\ntype Customer struct {\n\tID        int\n\tEmail     string\n\tFirstName *string        // use pointer to represent null\n\tLastName  sql.NullString // use sql.NullString to represent null\n}\n```\n\n## Quoting Table and Column Names\n\nDatabases vary in quoting table and column names. To allow writing DB-agnostic SQLs, ozzo-dbx introduces a special\nsyntax in quoting table and column names. A word enclosed within `{{` and `}}` is treated as a table name and will\nbe quoted according to the particular DB driver. Similarly, a word enclosed within `[[` and `]]` is treated as a \ncolumn name and will be quoted accordingly as well. For example, when working with a MySQL database, the following\nquery will be properly quoted:\n\n```go\n// SELECT * FROM `users` WHERE `status`=1\nq := db.NewQuery(\"SELECT * FROM {{users}} WHERE [[status]]=1\")\n```\n\nNote that if a table or column name contains a prefix, it will still be properly quoted. For example, `{{public.users}}`\nwill be quoted as `\"public\".\"users\"` for PostgreSQL.\n\n## Using Transactions\n\nYou can use all aforementioned query execution and building methods with transaction. For example,\n\n```go\ndb, _ := dbx.Open(\"mysql\", \"user:pass@/example\")\n\ntx, _ := db.Begin()\n\n_, err1 := tx.Insert(\"users\", dbx.Params{\n\t\"name\": \"user1\",\n}).Execute()\n_, err2 := tx.Insert(\"users\", dbx.Params{\n\t\"name\": \"user2\",\n}).Execute()\n\nif err1 == nil \u0026\u0026 err2 == nil {\n\ttx.Commit()\n} else {\n\ttx.Rollback()\n}\n```\n\nYou may use `DB.Transactional()` to simplify your transactional code without explicitly committing or rolling back\ntransactions. The method will start a transaction and automatically roll back the transaction if the callback\nreturns an error. Otherwise it will\nautomatically commit the transaction.\n\n\n```go\ndb, _ := dbx.Open(\"mysql\", \"user:pass@/example\")\n\nerr := db.Transactional(func(tx *dbx.Tx) error {\n\tvar err error\n\t_, err = tx.Insert(\"users\", dbx.Params{\n\t\t\"name\": \"user1\",\n\t}).Execute()\n\tif err != nil {\n\t\treturn err\n\t}\n\t_, err = tx.Insert(\"users\", dbx.Params{\n\t\t\"name\": \"user2\",\n\t}).Execute()\n\treturn err\n})\n\nfmt.Println(err)\n```\n\n## Logging Executed SQL Statements\n\nYou can log and instrument DB queries by installing loggers with a DB connection. There are three kinds of loggers you\ncan install:\n* `DB.LogFunc`: this is called each time when a SQL statement is queried or executed. The function signature is the\n  same as that of `fmt.Printf`, which makes it very easy to use. \n* `DB.QueryLogFunc`: this is called each time when querying with a SQL statement.\n* `DB.ExecLogFunc`: this is called when executing a SQL statement.\n \nThe following example shows how you can make use of these loggers.\n\n```go\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"github.com/go-ozzo/ozzo-dbx\"\n)\n\nfunc main() {\n\tdb, _ := dbx.Open(\"mysql\", \"user:pass@/example\")\n\n\t// simple logging\n\tdb.LogFunc = log.Printf\n\n\t// or you can use the following more flexible logging\n\tdb.QueryLogFunc = func(ctx context.Context, t time.Duration, sql string, rows *sql.Rows, err error) {\n\t\tlog.Printf(\"[%.2fms] Query SQL: %v\", float64(t.Milliseconds()), sql))\n\t}\n\tdb.ExecLogFunc = func(ctx context.Context, t time.Duration, sql string, result sql.Result, err error) {\n\t\tlog.Printf(\"[%.2fms] Execute SQL: %v\", float64(t.Milliseconds()), sql))\n\t}\n\t// ...\n)\n``` \n\n## Supporting New Databases\n\nWhile `ozzo-dbx` provides out-of-box query building support for most major relational databases, its open architecture\nallows you to add support for new databases. The effort of adding support for a new database involves:\n\n* Create a struct that implements the `QueryBuilder` interface. You may use `BaseQueryBuilder` directly or extend it\n  via composition.\n* Create a struct that implements the `Builder` interface. You may extend `BaseBuilder` via composition.\n* Write an `init()` function to register the new builder in `dbx.BuilderFuncMap`.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgo-ozzo%2Fozzo-dbx","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgo-ozzo%2Fozzo-dbx","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgo-ozzo%2Fozzo-dbx/lists"}