From 8402f60f16599c203a8c0baed20194f4322c1cb1 Mon Sep 17 00:00:00 2001 From: Gani Georgiev Date: Fri, 1 Jul 2022 12:53:02 +0300 Subject: [PATCH] updated import paths and readme --- .travis.yml | 2 +- README.md | 77 ++++---- db_test.go | 5 +- docs/README-ru.md | 470 --------------------------------------------- example_test.go | 2 +- go.mod | 2 +- testdata/mysql.sql | 2 +- 7 files changed, 49 insertions(+), 511 deletions(-) delete mode 100644 docs/README-ru.md diff --git a/.travis.yml b/.travis.yml index 7bcc020..ee38f9a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,7 +14,7 @@ install: - go get golang.org/x/lint/golint before_script: - - mysql -e 'CREATE DATABASE ozzo_dbx_test;'; + - mysql -e 'CREATE DATABASE pocketbase_dbx_test;'; script: - test -z "`gofmt -l -d .`" diff --git a/README.md b/README.md index 1632c03..ac665eb 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,12 @@ -# ozzo-dbx +dbx +[![Go Report Card](https://goreportcard.com/badge/github.com/pocketbase/dbx)](https://goreportcard.com/report/github.com/pocketbase/dbx) +[![GoDoc](https://godoc.org/github.com/pocketbase/dbx?status.svg)](https://pkg.go.dev/github.com/pocketbase/dbx) +================================================================================ + +> ⚠️ This is a maintained fork of [go-ozzo/ozzo-dbx](https://github.com/go-ozzo/ozzo-dbx) (see [#103](https://github.com/go-ozzo/ozzo-dbx/issues/103)). +> +> Currently, the changes are primarily related to better SQLite support and some other minor improvements, implementing [#99](https://github.com/go-ozzo/ozzo-dbx/pull/99), [#100](https://github.com/go-ozzo/ozzo-dbx/pull/100) and [#102](https://github.com/go-ozzo/ozzo-dbx/pull/102). -[![GoDoc](https://godoc.org/github.com/go-ozzo/ozzo-dbx?status.png)](http://godoc.org/github.com/go-ozzo/ozzo-dbx) -[![Build Status](https://travis-ci.org/go-ozzo/ozzo-dbx.svg?branch=master)](https://travis-ci.org/go-ozzo/ozzo-dbx) -[![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) -[![Go Report](https://goreportcard.com/badge/github.com/go-ozzo/ozzo-dbx)](https://goreportcard.com/report/github.com/go-ozzo/ozzo-dbx) ## Summary @@ -31,14 +34,11 @@ - [Logging Executed SQL Statements](#logging-executed-sql-statements) - [Supporting New Databases](#supporting-new-databases) -## Other Languages - -[Русский](/docs/README-ru.md) ## Description -ozzo-dbx is a Go package that enhances the standard `database/sql` package by providing powerful data retrieval methods -as well as DB-agnostic query building capabilities. ozzo-dbx is not an ORM. It has the following features: +`dbx` is a Go package that enhances the standard `database/sql` package by providing powerful data retrieval methods +as well as DB-agnostic query building capabilities. `dbx` is not an ORM. It has the following features: * Populating data into structs and NullString maps * Named parameter binding @@ -60,14 +60,14 @@ Go 1.13 or above. Run the following command to install the package: ``` -go get github.com/go-ozzo/ozzo-dbx +go get github.com/pocketbase/dbx ``` In addition, install the specific DB driver package for the kind of database to be used. Please refer to [SQL database drivers](https://github.com/golang/go/wiki/SQLDrivers) for a complete list. For example, if you are using MySQL, you may install the following package: -``` +```sh go get github.com/go-sql-driver/mysql ``` @@ -95,9 +95,10 @@ solve the problem. Please see the last section for more details. The following code snippet shows how you can use this package in order to access data from a MySQL database. ```go +package main + import ( - "fmt" - "github.com/go-ozzo/ozzo-dbx" + "github.com/pocketbase/dbx" _ "github.com/go-sql-driver/mysql" ) @@ -111,22 +112,22 @@ func main() { var users []struct { ID, Name string } - err := q.All(&users) + q.All(&users) // fetch a single row into a struct var user struct { ID, Name string } - err = q.One(&user) + q.One(&user) // fetch a single row into a string map data := dbx.NullStringMap{} - err = q.One(data) + q.One(data) // fetch row by row rows2, _ := q.Rows() for rows2.Next() { - _ = rows2.ScanStruct(&user) + rows2.ScanStruct(&user) // rows.ScanMap(data) // rows.Scan(&id, &name) } @@ -136,9 +137,10 @@ func main() { And the following example shows how to use the query building capability of this package. ```go +package main + import ( - "fmt" - "github.com/go-ozzo/ozzo-dbx" + "github.com/pocketbase/dbx" _ "github.com/go-sql-driver/mysql" ) @@ -156,11 +158,11 @@ func main() { var users []struct { ID, Name string } - err := q.All(&users) + q.All(&users) // build an INSERT query // INSERT INTO `users` (`name`) VALUES ('James') - err = db.Insert("users", dbx.Params{ + db.Insert("users", dbx.Params{ "name": "James", }).Execute() } @@ -209,7 +211,7 @@ type User struct { var ( users []User - user User + user User row dbx.NullStringMap @@ -269,7 +271,7 @@ The following example shows how fields are populated according to the rules abov ```go type User struct { id int - Type int `db:"-"` + Type int `db:"-"` MyName string `db:"name"` Profile Address Address `db:"addr"` @@ -299,7 +301,7 @@ if a struct field does not have a corresponding column in the result, it will no A SQL statement is usually parameterized with dynamic values. For example, you may want to select the user record according to the user ID received from the client. Parameter binding should be used in this case, and it is almost always preferred to prevent from SQL injection attacks. Unlike `database/sql` which does anonymous parameter binding, -`ozzo-dbx` uses named parameter binding. *Anonymous parameter binding is not supported*, as it will mess up with named +`dbx` uses named parameter binding. *Anonymous parameter binding is not supported*, as it will mess up with named parameters. For example, ```go @@ -342,7 +344,7 @@ err := q.WithContext(ctx).All(&users) ## Building Queries -Instead of writing plain SQLs, `ozzo-dbx` allows you to build SQLs programmatically, which often leads to cleaner, +Instead of writing plain SQLs, `dbx` allows you to build SQLs programmatically, which often leads to cleaner, more secure, and DB-agnostic code. You can build three types of queries: the SELECT queries, the data manipulation queries, and the schema manipulation queries. @@ -379,7 +381,7 @@ other interesting work. ### Building Query Conditions -`ozzo-dbx` supports very flexible and powerful query condition building which can be used to build SQL clauses +`dbx` supports very flexible and powerful query condition building which can be used to build SQL clauses such as `WHERE`, `HAVING`, etc. For example, ```go @@ -469,7 +471,7 @@ err := q.Execute() ## CRUD Operations -Although ozzo-dbx is not an ORM, it does provide a very convenient way to do typical CRUD (Create, Read, Update, Delete) +Although `dbx` is not an ORM, it does provide a very convenient way to do typical CRUD (Create, Read, Update, Delete) operations without the need of writing plain SQL statements. To use the CRUD feature, first define a struct type for a table. By default, a struct is associated with a table @@ -632,7 +634,7 @@ type Customer struct { ## Quoting Table and Column Names -Databases vary in quoting table and column names. To allow writing DB-agnostic SQLs, ozzo-dbx introduces a special +Databases vary in quoting table and column names. To allow writing DB-agnostic SQLs, `dbx` introduces a special syntax in quoting table and column names. A word enclosed within `{{` and `}}` is treated as a table name and will be quoted according to the particular DB driver. Similarly, a word enclosed within `[[` and `]]` is treated as a column name and will be quoted accordingly as well. For example, when working with a MySQL database, the following @@ -707,10 +709,15 @@ can install: The following example shows how you can make use of these loggers. ```go +package main + import ( - "fmt" + "context" + "database/sql" "log" - "github.com/go-ozzo/ozzo-dbx" + "time" + + "github.com/pocketbase/dbx" ) func main() { @@ -721,18 +728,18 @@ func main() { // or you can use the following more flexible logging db.QueryLogFunc = func(ctx context.Context, t time.Duration, sql string, rows *sql.Rows, err error) { - log.Printf("[%.2fms] Query SQL: %v", float64(t.Milliseconds()), sql)) + log.Printf("[%.2fms] Query SQL: %v", float64(t.Milliseconds()), sql) } db.ExecLogFunc = func(ctx context.Context, t time.Duration, sql string, result sql.Result, err error) { - log.Printf("[%.2fms] Execute SQL: %v", float64(t.Milliseconds()), sql)) + log.Printf("[%.2fms] Execute SQL: %v", float64(t.Milliseconds()), sql) } // ... -) +} ``` ## Supporting New Databases -While `ozzo-dbx` provides out-of-box query building support for most major relational databases, its open architecture +While `dbx` provides out-of-box query building support for most major relational databases, its open architecture allows you to add support for new databases. The effort of adding support for a new database involves: * Create a struct that implements the `QueryBuilder` interface. You may use `BaseQueryBuilder` directly or extend it diff --git a/db_test.go b/db_test.go index 8d3f0f3..e8e68cd 100644 --- a/db_test.go +++ b/db_test.go @@ -12,12 +12,13 @@ import ( "strings" "testing" + // @todo change to sqlite _ "github.com/go-sql-driver/mysql" "github.com/stretchr/testify/assert" ) const ( - TestDSN = "travis:@/ozzo_dbx_test?parseTime=true" + TestDSN = "travis:@/pocketbase_dbx_test?parseTime=true" FixtureFile = "testdata/mysql.sql" ) @@ -360,7 +361,7 @@ func getPreparedDB() *DB { return db } -// Naming according to issue 49 ( https://github.com/go-ozzo/ozzo-dbx/issues/49 ) +// Naming according to issue 49 ( https://github.com/pocketbase/dbx/issues/49 ) type ArtistDAO struct { nickname string diff --git a/docs/README-ru.md b/docs/README-ru.md deleted file mode 100644 index 12e5f0f..0000000 --- a/docs/README-ru.md +++ /dev/null @@ -1,470 +0,0 @@ -# ozzo-dbx - -[![Build Status](https://travis-ci.org/go-ozzo/ozzo-dbx.svg?branch=master)](https://travis-ci.org/go-ozzo/ozzo-dbx) -[![GoDoc](https://godoc.org/github.com/go-ozzo/ozzo-dbx?status.png)](http://godoc.org/github.com/go-ozzo/ozzo-dbx) - -ozzo-dbx это Go-пакет, который расширяет стандартный пакет `database/sql`, путем предоставления мощных методов извлечения данных, -а также позволяет использовать DB-agnostic (независимый от БД) построитель запросов. Он имеет следующие особенности: - -* Заполнение данных в структуры или NullString карты -* Именованные параметры связывания -* DB-agnostic методы построения запросов, включая SELECT, запросы на манипуляцию с данными и запросы на манипуляцию со схемой (структурой) БД -* Мощный построитель запросов с условиями -* Открытая архитектура, позволяющая с легкостью создавать поддержку для новых баз данных или кастомизировать текущую поддержку -* Логирование выполненных SQL запросов -* Предоставляет поддержку основных реляционных баз данных - -## Требования - -Go 1.2 или выше. - -## Установка - -Выполните данные команды для установки: - -``` -go get github.com/go-ozzo/ozzo-dbx -``` - -В дополнение, установите необходимый пакет драйвера базы данных для той базы, которая будет использоваться. Пожалуйста обратитесь к -[SQL database drivers](https://github.com/golang/go/wiki/SQLDrivers) для получения полного списка. Например, если вы используете -MySQL, вы можете загрузить этот пакет: - -``` -go get github.com/go-sql-driver/mysql -``` - -и импортировать его в ваш основной код следующим образом: - -```go -import _ "github.com/go-sql-driver/mysql" -``` - -## Поддерживаемые базы данных - -Представленные базы данных уже имеют поддержку из коробки: - -* SQLite -* MySQL -* PostgreSQL -* MS SQL Server (2012 или выше) -* Oracle - -Другие базы данных также могут работать. Если нет, вы можете создать для него свой построитель, как описано далее в этом документе. - - -## С чего начать - -Представленный ниже код показывает как вы можете использовать пакет для доступа к данным базы данных MySQL. - -```go -import ( - "fmt" - "github.com/go-ozzo/ozzo-dbx" - _ "github.com/go-sql-driver/mysql" -) - -func main() { - db, _ := dbx.Open("mysql", "user:pass@/example") - - // создаем новый запрос - q := db.NewQuery("SELECT id, name FROM users LIMIT 10") - - // извлекаем все строки в срез структур - var users []struct { - ID, Name string - } - q.All(&users) - - // извлекаем одну строку в структуру - var user struct { - ID, Name string - } - q.One(&user) - - // извлекаем строку в строковую карту - data := dbx.NullStringMap{} - q.One(data) - - // извлечение строку за строкой - rows2, _ := q.Rows() - for rows2.Next() { - rows2.ScanStruct(&user) - // rows.ScanMap(data) - // rows.Scan(&id, &name) - } -} -``` - -Следующий пример показывает, как можно использовать возможности построителя запросов из этого пакета. - -```go -import ( - "fmt" - "github.com/go-ozzo/ozzo-dbx" - _ "github.com/go-sql-driver/mysql" -) - -func main() { - db, _ := dbx.Open("mysql", "user:pass@/example") - - // строим SELECT запрос - // SELECT `id`, `name` FROM `users` WHERE `name` LIKE '%Charles%' ORDER BY `id` - q := db.Select("id", "name"). - From("users"). - Where(dbx.Like("name", "Charles")). - OrderBy("id") - - // извлекаем все строки в срез структур - var users []struct { - ID, Name string - } - q.All(&users) - - // строим INSERT запрос - // INSERT INTO `users` (`name`) VALUES ('James') - db.Insert("users", dbx.Params{ - "name": "James", - }).Execute() -} -``` - -## Соединение с базой данных - -Для соединения с базой данных, используйте `dbx.Open()` точно таким же образом, как вы могли бы сделать это при помощи `Open()` метода в `database/sql`. - -```go -db, err := dbx.Open("mysql", "user:pass@hostname/db_name") -``` - -Метод возвращает экземпляр `dbx.DB` который можно использовать для создания и выполнения запросов к БД. Обратите внимание, -что метод на самом деле не устанавливает соединение до тех пор пока вы не выполните запрос с использованием экземпляра `dbx.DB`. Он так же -не проверяет корректность имени источника данных. Выполните `dbx.MustOpen()` для того чтобы убедиться, что имя базы данных правильное. - -## Выполнение запросов - -Для выполнения SQL запроса, сначала создайте экземпляр `dbx.Query`, и далее создайте запрос при помощи `DB.NewQuery()` с SQL выражением, -которое необходимо исполнить. И затем выполните `Query.Execute()` для исполнения запроса, в случае если запрос не предназначен для извлечения данных. -Например, - -```go -q := db.NewQuery("UPDATE users SET status=1 WHERE id=100") -result, err := q.Execute() -``` - -Если SQL запрос должен вернуть данные (такой как SELECT), следует вызвать один из нижепреведенных методов, -которые выполнят запрос и сохранят результат в указанной переменной/переменных. - -* `Query.All()`: заполняет массив структур или `NullString` карты всеми строками результата. -* `Query.One()`: сохраняет первую строку из результата в структуру или в `NullString` карту. -* `Query.Row()`: заполняет список переменных первой строкой результата, каждая перменная заполняется данными одной из возвращаемых колонок. -* `Query.Rows()`: возвращает экземпляр `dbx.Rows` для обеспечения дальнейшей возможности извлечения данных методом строка за строкой. - -Например, - -```go -type User struct { - ID int - Name string -} - -var ( - users []User - user User - - row dbx.NullStringMap - - id int - name string - - err error -) - -q := db.NewQuery("SELECT id, name FROM users LIMIT 10") - -// заполняет срез User всеми строками из запроса -err = q.All(&users) -fmt.Println(users[0].ID, users[0].Name) - -// заполняет структуру User данными из первой строки -err = q.One(&user) -fmt.Println(user.ID, user.Name) - -// запоминает первую строку в карту NullString -err = q.One(&row) -fmt.Println(row["id"], row["name"]) - -// заполняет переменные id и name данными из первой строки -err = q.Row(&id, &name) - -// заполнят данные методом строка за строкой -rows, _ := q.Rows() -for rows.Next() { - rows.ScanMap(&row) -} -``` - -При заполнении структуры, данные правила используются для определения какая колонка будет сохранена в какое поле структуры: - -* Только экспортируемые поля структуры будут заполнены. -* Поле принимает данные, если его имя имеет отображение к столбцу в соответствии с функцией отображения `Query.FieldMapper`. - Функция отображения поля по умолчанию разделяет слова в имени поля подчеркиванием и приводит их к нижнему регистру. - Например, поле `FirstName` будет отображено в имя столбца `first_name`, и `MyID` в `my_id`. -* Если поле имеет `db` тег, значение тега будет использовано для опредления соответствующего имени столбца. Если `db` тег имеет `-`, - это обозначает, что поле НЕ будет заполнено. -* Анонимные поля типа структуры будут расширены и будут заполнены в соответствии с правилами описанными выше. -* Именованные поля типа структуры также будут раширяться. Но их составные поля будут иметь префикс с именем структуры при заполнении. - -Представленный ниже пример показывает, как поля будут заполняться в соответствии с указанными выше правилами: - -```go -type User struct { - id int - Type int `db:"-"` - MyName string `db:"name"` - Prof Profile -} - -type Profile struct { - Age int -} -``` - -* `User.id`: не будет заполнено в следствие того, что поле id не экспортируется (т.к. оно записано с маленькой буквы); -* `User.Type`: не будет заполнено потому что поле имеет `db` тег `-`; -* `User.MyName`: будет заполнено из столбца `name`, в соответствии с тегом `db`; -* `Profile.Age`: будет заполнено из столбца `prof.age`, т.к. `Prof` имя поля типа структуры и оно получит префикс `prof.`. - -Обратите внимание, что если столбец не имеет соответствующего поля в структуре, он будет проигнорирован. По аналогии, если поле структуры не имееет соответствующего столбца в результате, то оно не будет заполнено. - -## Связывание параметров - -SQL запросы, как правило, имеют димамические значения. Например, вы можете выбрать запись пользоателя в соответствии с ID пользователя, полученного от клиента. В этом случае должно быть выполнено связывание параметров, и это почти всегда предпочтительно в целях обеспечения безопасности. В отличии от `database/sql` которая разрешает анонимное связывание, `ozzo-dbx` использует для связывания именованые параметры. Например, - -```go -q := db.NewQuery("SELECT id, name FROM users WHERE id={:id}") -q.Bind(dbx.Params{"id": 100}) -q.One(&user) -``` - -Приведенный выше пример выберет пользователя `id` которого 100. Метод `Query.Bind()` связывает набор из именовынных параметров с SQL запросом который содержит плейсхолдеры в формате `{:ParamName}`. - -Если оператор SQL должен быть выполнен несколько раз с различными параметрами, он должен быть подготовлен для увеличения производительности. Например, - -```go -q := db.NewQuery("SELECT id, name FROM users WHERE id={:id}") -q.Prepare() - -q.Bind(dbx.Params{"id": 100}) -q.One(&user) - -q.Bind(dbx.Params{"id": 200}) -q.One(&user) - -// ... -``` - -Обратите внимание, что анонимные параметры не поддерживаются, т.к. это внесет беспорядок в именованное связывание. - -## Построение запросов - -Вместо того чтобы писать обычные SQLs запросы, `ozzo-dbx` позволяет строить SQL запросы программно, что чаще всего приводит к чистоте кода и большей защищенности, а так делает код не зависимым от используемой базы данных. Вы можете построить три типа запросов: SELECT запросы, запросы для манипуляции с данными и запросы для манипуляции со схемой (структурой) БД. - -### Построение SELECT запросов - -Построение SELECT запроса начинается с вызова `DB.Select()`. Вы можете использовать различные условия для SELECT запросов, используя соответствующие методы построения запросов. Например, - -```go -db, _ := dbx.Open("mysql", "user:pass@/example") -db.Select("id", "name"). - From("users"). - Where(dbx.HashExp{"id": 100}). - One(&user) -``` - -Приведенный выше код будет генерировать следующий SQL запрос: - -```sql -SELECT `id`, `name` FROM `users` WHERE `id`={:p0} -``` - -Обратите внимание, что название таблицы и имена стобцов будут правильно экранированы в сосответствии с типом используемой базы данных. -И параметр подстановки значения `p0` попадет в условие `WHERE`. - -Каждое ключевое слово SQL имеет свой соответствующий метод в построителе запросов. Например, `SELECT` соответствет `Select()`, -`FROM` соответствует `From()`, `WHERE` соответствует `Where()`, и так далее. Вы можете использовать эти методы совместно, как и в обычном SQL запросе. Каждый из этих методов возвращает экземпляр запроса (типа `dbx.SelectQuery`) который строится. -Как только вы закончите построения запроса, вы можете вызвать методы, такие как `One()`, `All()` для выполнения запроса и и сохранения данных в переменные. Также вы можете явно вызвать `Build()` для построения запроса и превратить его в экземпляр `dbx.Query` что может помоч вам получить SQL выражение и делать другую интересную работу. - -### Построение условий запроса - -`ozzo-dbx` поддерживает очень гибкий и мощный построитель условий для запроса, который может быть использован для SQL выражений -таких как `WHERE`, `HAVING`, и т.д. Например, - -```go -// id=100 -dbx.NewExp("id={:id}", dbx.Params{"id": 100}) - -// id=100 AND status=1 -dbx.HashExp{"id": 100, "status": 1} - -// status=1 OR age>30 -dbx.Or(dbx.HashExp{"status": 1}, dbx.NewExp("age>30")) - -// name LIKE '%admin%' AND name LIKE '%example%' -dbx.Like("name", "admin", "example") -``` - -При построении выражения условий в запросе, значение его параметров будет заполнено с помощью параметрического связывания, которое предотвращает использование SQL инекций. Кроме того, если выражение содержит имена столбцов, они будут правильно экранированы. -Доступны слудующие функции для построениея условий: - -* `dbx.NewExp()`: создает условие используя заданное строкового выражение и связываемый параметр. Например, -`dbx.NewExp("id={:id}", dbx.Params{"id":100})` создаст выражение `id=100`. -* `dbx.HashExp`: подставляет пары имя:значение в `AND` оператор. Например, -`dbx.HashExp{"id":100, "status":1}` создает `id=100 AND status=1`. -* `dbx.Not()`: создает `NOT` выражение подставляя `NOT` в заданное выражение. -* `dbx.And()`: создает `AND` выражение путем объединения заданных выражений при помощи `AND` оператора. -* `dbx.Or()`: создает выражение `OR` путем объединения заданных выражений при помощи оператора `OR`. -* `dbx.In()`: создает `IN` выражение для указанного столбца и диапазона значений. -Например, `dbx.In("age", 30, 40, 50)` создаст выражение `age IN (30, 40, 50)`. -Обратите внимание, что, если диапазон значений пуст, он будет генерировать выражение, представляющее ложное значение. -* `dbx.NotIn()`: создает `NOT IN` выражение. Что очень похоже на `dbx.In()`. -* `dbx.Like()`: создает `LIKE` выражение для указанного столбца и диапазона значений. Например, -`dbx.Like("title", "golang", "framework")` создаст выражение `title LIKE "%golang%" AND title LIKE "%framework%"`. -Вы можете дополнить LIKE выражение при помощи `Escape()` и/или `Match()` функции полученного выражения. -Обратите внимание, что, если диапазон значений пуст, он будет генерировать пустое выражение. -* `dbx.NotLike()`: создает `NOT LIKE` выражение. Что очень похоже на `dbx.Like()`. -* `dbx.OrLike()`: создает `LIKE` выражение объединением различных `LIKE` подвыражений при помощи `OR` вместо `AND`. -* `dbx.OrNotLike()`: создает `NOT LIKE` выражение путем объединения `NOT LIKE` выражений используя `OR` вместо `AND`. -* `dbx.Exists()`: создает `EXISTS` выражение путем добавления `EXISTS` к заданному выражению. -* `dbx.NotExists()`: создает `NOT EXISTS` выражение путем добавления `NOT EXISTS` к заданному выражению. -* `dbx.Between()`: создает `BETWEEN` выражение. Например, `dbx.Between("age", 30, 40)`создает выражение `age BETWEEN 30 AND 40`. -* `dbx.NotBetween()`: создает `NOT BETWEEN` выражение. - -Вы также можете создавать другие удобные функции для помощи в построении условий, таким образом, чтобы функция возвращала -объект реализующий интерфейс `dbx.Expression`. - -### Построение запросов для манипуляции с данными - -Запросы манипуляции с данными это запросы которые изменяют данные в базе данных, такие как INSERT, UPDATE, DELETE операторы. -Такого рода запросы могут быть построены путем вызова соответствующих методов `DB`. Например, - -```go -db, _ := dbx.Open("mysql", "user:pass@/example") - -// INSERT INTO `users` (`name`, `email`) VALUES ({:p0}, {:p1}) -db.Insert("users", dbx.Params{ - "name": "James", - "email": "james@example.com", -}).Execute() - -// UPDATE `users` SET `status`={:p0} WHERE `id`={:p1} -db.Update("users", dbx.Params{"status": 1}, dbx.HashExp{"id": 100}).Execute() - -// DELETE FROM `users` WHERE `status`={:p0} -db.Delete("users", dbx.HashExp{"status": 2}).Execute() -``` - -При построении запросов на манипуляцию с данными, не забудьте в конце использовать `Execute()` для выполнения запроса. - -### Построение запросов для работы со схемой (структурой) БД - -Запросы для манипулирования со схемой БД изменяют структуру БД, то есть создают новую таблицу, добавляют новый столбец и т.д. -Эти запросы могут быть построены путем вызова соответствующих методов `DB`. Например, - -```go -db, _ := dbx.Open("mysql", "user:pass@/example") - -// CREATE TABLE `users` (`id` int primary key, `name` varchar(255)) -q := db.CreateTable("users", map[string]string{ - "id": "int primary key", - "name": "varchar(255)", -}) -q.Execute() -``` - -## Экранирование названия таблиц и столбцов - -Различные базы данных по разному экранируют (заключают в кавычки) название таблиц и названия столбцов. Для возможности писать SQL запросы, независимые от БД (DB-agnostic SQLs), ozzo-dbx предоставляет специальный синтакс для экранирования названия имен таблиц и столбцов. Слово заключенное в `{{` и `}}` трактуется как имя таблицы и будет экранировано в соответствии с используемым драйвером БД. Подобным образом слово заключенное в `[[` и `]]` трактуется как имя столбца и также будет правильно экранировано. Например, при работе с базой данных MySQL, следующий запрос будет должным образом экранирован: - -```go -// SELECT * FROM `users` WHERE `status`=1 -q := db.NewQuery("SELECT * FROM {{users}} WHERE [[status]]=1") -``` - -Обратите внимание, что если имя таблицы или столбца содержит префикс, он все равно будет правильно проэкранирован. Например, `{{public.users}}` -будет экранирован как `"public"."users"` для PostgreSQL. - -## Использование транзакций - -Вы можете использовать все возможные методы для выполнения запросов с использованием транзакций. Например, - -```go -db, _ := dbx.Open("mysql", "user:pass@/example") - -tx, _ := db.Begin() - -_, err1 := tx.Insert("users", dbx.Params{ - "name": "user1", -}).Execute() -_, err2 := tx.Insert("users", dbx.Params{ - "name": "user2", -}).Execute() - -if err1 == nil && err2 == nil { - tx.Commit() -} else { - tx.Rollback() -} -``` - -## Логирование исполеннных SQL запросов - -Когда `DB.LogFunc` настроен для логирования, все SQL будут выполены и сохранены в лог. -В следующем примере показано как сконфигурировать логгер при использования стандартного `log` пакета: - -```go -import ( - "fmt" - "log" - "github.com/go-ozzo/ozzo-dbx" -) - -func main() { - db, _ := dbx.Open("mysql", "user:pass@/example") - db.LogFunc = log.Printf - - // ... -) -``` - -А этот пример показывет как применять `ozzo-log` пакет, который позволяет использовать уровни важности и категории, -а также отправлять сообщения различным получателям (таким как файлы, окно консоли, сетевое устройство).: - -```go -import ( - "fmt" - "github.com/go-ozzo/ozzo-dbx" - "github.com/go-ozzo/ozzo-log" - _ "github.com/go-sql-driver/mysql" -) - -func main() { - logger := log.NewLogger() - logger.Targets = []log.Target{log.NewConsoleTarget()} - logger.Open() - - db, _ := dbx.Open("mysql", "user:pass@/example") - db.LogFunc = logger.Info - - // ... -) -``` - -## Поддержка дополнительных баз данных - -Не смотря на то, что `ozzo-dbx` "из коробки" предоставляет поддержку всех основных реляционных баз данных, его окрытая архитектура -позволяет вам добавлять поддержку новых баз данных. Действия для добавления новой базы данных включают в себя: - -* создание структуры, которая имплементирует интерфейс `QueryBuilder`. Вы можете использовать `BaseQueryBuilder` напрямую или расширить его функциональность. -* Создать структуру которая имплементирует интерфейс `Builder`. Вы можете расширить `BaseBuilder` с помощью композиции. -* Напишите `init()` функцию для регистрации нового построителя в `dbx.BuilderFuncMap`. diff --git a/example_test.go b/example_test.go index 5b0f864..c0909cd 100644 --- a/example_test.go +++ b/example_test.go @@ -3,7 +3,7 @@ package dbx_test import ( "fmt" - "github.com/go-ozzo/ozzo-dbx" + "github.com/pocketbase/dbx" ) // This example shows how to populate DB data in different ways. diff --git a/go.mod b/go.mod index 9461d26..e9cb0e5 100644 --- a/go.mod +++ b/go.mod @@ -1,4 +1,4 @@ -module github.com/go-ozzo/ozzo-dbx +module github.com/pocketbase/dbx go 1.13 diff --git a/testdata/mysql.sql b/testdata/mysql.sql index cdaef68..b09a0bd 100644 --- a/testdata/mysql.sql +++ b/testdata/mysql.sql @@ -4,7 +4,7 @@ * - host: 127.0.0.1 * - user: travis * - pass: - * - database: ozzo_dbx_test + * - database: pocketbase_dbx_test */ DROP TABLE IF EXISTS `order_item` CASCADE;