src/db_connector/db_sqlite
nimble install db_connector. Обёртка уровня выше для базы данных SQLite. Этот интерфейс реализован и для других баз данных.
Основные примеры использования
Основные действия при использовании этого модуля:
- Открытие подключения к базе данных
- Выполнение SQL запроса
- Закрытие подключения к базе данных
Подстановка параметров
Все модули db_* поддерживают одинаковую форму подстановки параметров. То есть, используется ? (вопросительный знак) для обозначения места, куда нужно поместить значение. Например:
sql"INSERT INTO my_table (colA, colB, colC) VALUES (?, ?, ?)"
Открытие подключения к базе данных
import db_connector/db_sqlite
# user, password, database name can be empty.
# These params are not used on db_sqlite module.
let db = open("mytest.db", "", "", "")
db.close() Создание таблицы
db.exec(sql"DROP TABLE IF EXISTS my_table")
db.exec(sql"""CREATE TABLE my_table (
id INTEGER,
name VARCHAR(50) NOT NULL
)""") Вставка данных
db.exec(sql"INSERT INTO my_table (id, name) VALUES (0, ?)",
"Jack") Более сложный пример
import db_connector/db_sqlite
import std/math
let db = open("mytest.db", "", "", "")
db.exec(sql"DROP TABLE IF EXISTS my_table")
db.exec(sql"""CREATE TABLE my_table (
id INTEGER PRIMARY KEY,
name VARCHAR(50) NOT NULL,
i INT(11),
f DECIMAL(18, 10)
)""")
db.exec(sql"BEGIN")
for i in 1..1000:
db.exec(sql"INSERT INTO my_table (name, i, f) VALUES (?, ?, ?)",
"Item#" & $i, i, sqrt(i.float))
db.exec(sql"COMMIT")
for x in db.fastRows(sql"SELECT * FROM my_table"):
echo x
let id = db.tryInsertId(sql"""INSERT INTO my_table (name, i, f)
VALUES (?, ?, ?)""",
"Item#1001", 1001, sqrt(1001.0))
echo "Inserted item: ", db.getValue(sql"SELECT name FROM my_table WHERE id=?", id)
db.close() Пример хранения двоичных данных
import std/random
## Generate random float datas
var orig = newSeq[float64](150)
randomize()
for x in orig.mitems:
x = rand(1.0)/10.0
let db = open("mysqlite.db", "", "", "")
block: ## Create database
## Binary datas needs to be of type BLOB in SQLite
let createTableStr = sql"""CREATE TABLE test(
id INTEGER NOT NULL PRIMARY KEY,
data BLOB
)
"""
db.exec(createTableStr)
block: ## Insert data
var id = 1
## Data needs to be converted to seq[byte] to be interpreted as binary by bindParams
var dbuf = newSeq[byte](orig.len*sizeof(float64))
copyMem(unsafeAddr(dbuf[0]), unsafeAddr(orig[0]), dbuf.len)
## Use prepared statement to insert binary data into database
var insertStmt = db.prepare("INSERT INTO test (id, data) VALUES (?, ?)")
insertStmt.bindParams(id, dbuf)
let bres = db.tryExec(insertStmt)
## Check insert
doAssert(bres)
# Destroy statement
finalize(insertStmt)
block: ## Use getValue to select data
var dataTest = db.getValue(sql"SELECT data FROM test WHERE id = ?", 1)
## Calculate sequence size from buffer size
let seqSize = int(dataTest.len*sizeof(byte)/sizeof(float64))
## Copy binary string data in dataTest into a seq
var res: seq[float64] = newSeq[float64](seqSize)
copyMem(unsafeAddr(res[0]), addr(dataTest[0]), dataTest.len)
## Check datas obtained is identical
doAssert res == orig
db.close() Примечание
Этот модуль не реализует никаких функций ORM, таких как отображение типов из схемы. Вместо этого, для каждой строки возвращается seq[string].
Обоснование:
- Это близко к тому, что многие СУБД предлагают напрямую (
char**) - Это скрывает количество типов, которые поддерживает СУБД (int? int64? decimal до 10 знаков? геокоординаты?)
- Это удобно, когда всё, что вам нужно сделать, это передать данные куда-нибудь ещё (вывести, записать в журнал, поместить данные в новый запрос)
См. также
- Модуль db_odbc для обёртки базы данных ODBC
- Модуль db_mysql для обёртки базы данных MySQL
- Модуль db_postgres для обёртки базы данных PostgreSQL
Импорты
- sqlite3, db_common, dbutils
Типы
DbConn = PSqlite3
- Оборачивает соединение с базой данных.
InstantRow = PStmt
- Ручка, которая может использоваться для получения текстового представления столбца строки по требованию.
Row = seq[string]
- Строка набора данных.
NULLзначения базы данных будут преобразованы в пустую строку. SqlPrepared = distinct PStmt
- идентификатор подготовленных запросов
Процедуры
proc `[]`(row: InstantRow; col: int32): string {.inline, ...raises: [], tags: [], forbids: [].}-
Возвращает текст для заданного столбца строки.
См. также:
- Итератор instantRows пример кода
proc bindNull(ps: SqlPrepared; paramIdx: int) {....raises: [DbError], tags: [], forbids: [].}proc bindParam(ps: SqlPrepared; paramIdx: int; val: float64) {. ...raises: [DbError], tags: [], forbids: [].}proc bindParam(ps: SqlPrepared; paramIdx: int; val: int) {....raises: [DbError], tags: [], forbids: [].}proc bindParam(ps: SqlPrepared; paramIdx: int; val: int32) {....raises: [DbError], tags: [], forbids: [].}proc bindParam(ps: SqlPrepared; paramIdx: int; val: int64) {....raises: [DbError], tags: [], forbids: [].}proc bindParam(ps: SqlPrepared; paramIdx: int; val: openArray[byte]; copy = true) {. ...raises: [DbError], tags: [], forbids: [].}proc bindParam(ps: SqlPrepared; paramIdx: int; val: string; copy = true) {. ...raises: [DbError], tags: [], forbids: [].}proc close(db: DbConn) {....tags: [DbEffect], raises: [DbError], forbids: [].}-
Закрывает подключение к базе данных.
Примеры:
let db = open("mytest.db", "", "", "") db.close() proc dbError(db: DbConn) {.noreturn, ...raises: [DbError], tags: [], forbids: [].}-
Выбрасывает исключение
DbError.Примеры:
let db = open("mytest.db", "", "", "") if not db.tryExec(sql"SELECT * FROM not_exist_table"): dbError(db) db.close() proc dbQuote(s: string): string {....raises: [], tags: [], forbids: [].}- Экранирует символ
'(одинарная кавычка) в''. Так как одинарная кавычка используется для определенияVARCHARв SQL.Пример:
doAssert dbQuote("'") == "''''" doAssert dbQuote("A Foobar's pen.") == "'A Foobar''s pen.'" proc exec(db: DbConn; query: SqlQuery; args: varargs[string, `$`]) {. ...tags: [ReadDbEffect, WriteDbEffect], raises: [DbError], forbids: [].}-
Выполняет запрос и выбрасывает исключение
DbErrorпри неудаче.Примеры:
let db = open("mytest.db", "", "", "") try: db.exec(sql"INSERT INTO my_table (id, name) VALUES (?, ?)", 1, "item#1") except: stderr.writeLine(getCurrentExceptionMsg()) finally: db.close() proc execAffectedRows(db: DbConn; query: SqlQuery; args: varargs[string, `$`]): int64 {. ...tags: [ReadDbEffect, WriteDbEffect], raises: [DbError], forbids: [].}-
Выполняет запрос (обычно "UPDATE") и возвращает количество затронутых строк.
Примеры:
let db = open("mytest.db", "", "", "") # Records of my_table: # | id | name | # |----|----------| # | 1 | item#1 | # | 2 | item#2 | doAssert db.execAffectedRows(sql"UPDATE my_table SET name = 'TEST'") == 2 db.close() proc execAffectedRows(db: DbConn; stmtName: SqlPrepared): int64 {. ...tags: [ReadDbEffect, WriteDbEffect], raises: [DbError], forbids: [].}proc finalize(sqlPrepared: SqlPrepared) {.discardable, ...raises: [], tags: [], forbids: [].}proc getAllRows(db: DbConn; query: SqlQuery; args: varargs[string, `$`]): seq[ Row] {....tags: [ReadDbEffect], raises: [DbError], forbids: [].}-
Выполняет запрос и возвращает весь набор результатов.
Примеры:
let db = open("mytest.db", "", "", "") # Records of my_table: # | id | name | # |----|----------| # | 1 | item#1 | # | 2 | item#2 | doAssert db.getAllRows(sql"SELECT id, name FROM my_table") == @[Row(@["1", "item#1"]), Row(@["2", "item#2"])] db.close() proc getAllRows(db: DbConn; stmtName: SqlPrepared): seq[Row] {. ...tags: [ReadDbEffect, WriteDbEffect], raises: [DbError], forbids: [].}proc getRow(db: DbConn; query: SqlQuery; args: varargs[string, `$`]): Row {. ...tags: [ReadDbEffect], raises: [DbError], forbids: [].}-
Извлекает одну строку. Если запрос не возвращает строк, эта процедура вернёт
Rowс пустыми строками для каждого столбца.Примеры:
let db = open("mytest.db", "", "", "") # Records of my_table: # | id | name | # |----|----------| # | 1 | item#1 | # | 2 | item#2 | doAssert db.getRow(sql"SELECT id, name FROM my_table" ) == Row(@["1", "item#1"]) doAssert db.getRow(sql"SELECT id, name FROM my_table WHERE id = ?", 2) == Row(@["2", "item#2"]) # Returns empty. doAssert db.getRow(sql"INSERT INTO my_table (id, name) VALUES (?, ?)", 3, "item#3") == @[] doAssert db.getRow(sql"DELETE FROM my_table WHERE id = ?", 3) == @[] doAssert db.getRow(sql"UPDATE my_table SET name = 'ITEM#1' WHERE id = ?", 1) == @[] db.close() proc getValue(db: DbConn; query: SqlQuery; args: varargs[string, `$`]): string {. ...tags: [ReadDbEffect], raises: [DbError], forbids: [].}-
Выполняет запрос и возвращает первый столбец первой строки набора результатов. Возвращает
""если набор данных не содержит строк или значение базы данныхNULL.Примеры:
let db = open("mytest.db", "", "", "") # Records of my_table: # | id | name | # |----|----------| # | 1 | item#1 | # | 2 | item#2 | doAssert db.getValue(sql"SELECT name FROM my_table WHERE id = ?", 2) == "item#2" doAssert db.getValue(sql"SELECT id, name FROM my_table") == "1" doAssert db.getValue(sql"SELECT name, id FROM my_table") == "item#1" db.close() proc getValue(db: DbConn; stmtName: SqlPrepared): string {. ...tags: [ReadDbEffect, WriteDbEffect], raises: [], forbids: [].}proc insert(db: DbConn; query: SqlQuery; pkName: string; args: varargs[string, `$`]): int64 {....tags: [WriteDbEffect], raises: [DbError], forbids: [].}- то же самое, что и insertId
proc insertID(db: DbConn; query: SqlQuery; args: varargs[string, `$`]): int64 {. ...tags: [WriteDbEffect], raises: [DbError], forbids: [].}-
Выполняет запрос (обычно "INSERT") и возвращает сгенерированный ID для строки.
Выбрасывает исключение
DbErrorпри неудачной вставке строки. Для Postgre это добавляетRETURNING idк запросу, поэтому работает только если ваш первичный ключ называетсяid.Примеры:
let db = open("mytest.db", "", "", "") db.exec(sql"CREATE TABLE my_table (id INTEGER, name VARCHAR(50) NOT NULL)") for i in 0..2: let id = db.insertID(sql"INSERT INTO my_table (id, name) VALUES (?, ?)", i, "item#" & $i) echo "LoopIndex = ", i, ", InsertID = ", id # Output: # LoopIndex = 0, InsertID = 1 # LoopIndex = 1, InsertID = 2 # LoopIndex = 2, InsertID = 3 db.close() proc len(row: InstantRow): int32 {.inline, ...raises: [], tags: [], forbids: [].}-
Возвращает количество столбцов в строке.
См. также:
- Итератор instantRows пример кода
proc open(connection, user, password, database: string): DbConn {. ...tags: [DbEffect], raises: [DbError], forbids: [].}-
Открывает подключение к базе данных. Выбрасывает исключение
DbErrorесли подключение не удалось установить.Примечание: Только параметр
connectionиспользуется дляsqlite.Примеры:
try: let db = open("mytest.db", "", "", "") ## do something... ## db.getAllRows(sql"SELECT * FROM my_table") db.close() except: stderr.writeLine(getCurrentExceptionMsg()) proc prepare(db: DbConn; q: string): SqlPrepared {....raises: [DbError], tags: [], forbids: [].}- Создаёт новый объект
SqlPrepared. proc setEncoding(connection: DbConn; encoding: string): bool {....tags: [DbEffect], raises: [DbError], forbids: [].}-
Устанавливает кодировку подключения к базе данных, возвращает
trueпри успехе,falseпри неудаче.Примечание: Кодировку нельзя изменить после её установки. Согласно документации SQLite3, любая попытка изменить кодировку после создания базы данных будет проигнорирована.
proc tryExec(db: DbConn; query: SqlQuery; args: varargs[string, `$`]): bool {. ...tags: [ReadDbEffect, WriteDbEffect], raises: [DbError], forbids: [].}-
Пытается выполнить запрос и возвращает
trueпри успехе,falseв противном случае.Примеры:
let db = open("mytest.db", "", "", "") if not db.tryExec(sql"SELECT * FROM my_table"): dbError(db) db.close() proc tryExec(db: DbConn; stmtName: SqlPrepared): bool {. ...tags: [ReadDbEffect, WriteDbEffect], raises: [], forbids: [].}proc tryInsert(db: DbConn; query: SqlQuery; pkName: string; args: varargs[string, `$`]): int64 {....tags: [WriteDbEffect], raises: [DbError], forbids: [].}- то же самое, что и tryInsertID
proc tryInsertID(db: DbConn; query: SqlQuery; args: varargs[string, `$`]): int64 {. ...tags: [WriteDbEffect], raises: [DbError], forbids: [].}-
Выполняет запрос (обычно "INSERT") и возвращает сгенерированный ID для строки или -1 в случае ошибки.
Примеры:
let db = open("mytest.db", "", "", "") db.exec(sql"CREATE TABLE my_table (id INTEGER, name VARCHAR(50) NOT NULL)") doAssert db.tryInsertID(sql"INSERT INTO not_exist_table (id, name) VALUES (?, ?)", 1, "item#1") == -1 db.close() proc unsafeColumnAt(row: InstantRow; index: int32): cstring {.inline, ...raises: [], tags: [], forbids: [].}-
Возвращает cstring для заданного столбца строки.
См. также:
- Итератор instantRows пример кода
Итераторы
iterator fastRows(db: DbConn; query: SqlQuery; args: varargs[string, `$`]): Row {. ...tags: [ReadDbEffect], raises: [DbError, DbError], forbids: [].}-
Выполняет запрос и перебирает набор результатов.
Это очень быстро, но потенциально опасно. Используйте этот итератор только если вам нужны ВСЕ строки.
Примечание: Прерывание
fastRows()итератора во время цикла приведёт к тому, что следующий запрос к базе данных вызовет исключениеDbErrorunable to close due to ....Примеры:
let db = open("mytest.db", "", "", "") # Records of my_table: # | id | name | # |----|----------| # | 1 | item#1 | # | 2 | item#2 | for row in db.fastRows(sql"SELECT id, name FROM my_table"): echo row # Output: # @["1", "item#1"] # @["2", "item#2"] db.close() iterator fastRows(db: DbConn; stmtName: SqlPrepared): Row {. ...tags: [ReadDbEffect, WriteDbEffect], raises: [DbError], forbids: [].}iterator instantRows(db: DbConn; columns: var DbColumns; query: SqlQuery; args: varargs[string, `$`]): InstantRow {. ...tags: [ReadDbEffect], raises: [DbError, DbError], forbids: [].}-
Аналогичен итератору instantRows, но устанавливает информацию о столбцах в
columns.Примеры:
let db = open("mytest.db", "", "", "") # Records of my_table: # | id | name | # |----|----------| # | 1 | item#1 | # | 2 | item#2 | var columns: DbColumns for row in db.instantRows(columns, sql"SELECT * FROM my_table"): discard echo columns[0] # Output: # (name: "id", tableName: "my_table", typ: (kind: dbNull, # notNull: false, name: "INTEGER", size: 0, maxReprLen: 0, precision: 0, # scale: 0, min: 0, max: 0, validValues: @[]), primaryKey: false, # foreignKey: false) db.close() iterator instantRows(db: DbConn; query: SqlQuery; args: varargs[string, `$`]): InstantRow {. ...tags: [ReadDbEffect], raises: [DbError, DbError], forbids: [].}-
Аналогичен итератору fastRows, но возвращает ручку, которую можно использовать для получения текста столбца по требованию с помощью
[]. Возвращаемая ручка валидна только внутри тела итератора.Примеры:
let db = open("mytest.db", "", "", "") # Records of my_table: # | id | name | # |----|----------| # | 1 | item#1 | # | 2 | item#2 | for row in db.instantRows(sql"SELECT * FROM my_table"): echo "id:" & row[0] echo "name:" & row[1] echo "length:" & $len(row) # Output: # id:1 # name:item#1 # length:2 # id:2 # name:item#2 # length:2 db.close() iterator instantRows(db: DbConn; stmtName: SqlPrepared): InstantRow {. ...tags: [ReadDbEffect, WriteDbEffect], raises: [DbError], forbids: [].}iterator rows(db: DbConn; query: SqlQuery; args: varargs[string, `$`]): Row {. ...tags: [ReadDbEffect], raises: [DbError], forbids: [].}-
Аналогичен итератору fastRows, но медленнее и безопаснее.
Примеры:
let db = open("mytest.db", "", "", "") # Records of my_table: # | id | name | # |----|----------| # | 1 | item#1 | # | 2 | item#2 | for row in db.rows(sql"SELECT id, name FROM my_table"): echo row ## Output: ## @["1", "item#1"] ## @["2", "item#2"] db.close() iterator rows(db: DbConn; stmtName: SqlPrepared): Row {. ...tags: [ReadDbEffect, WriteDbEffect], raises: [DbError], forbids: [].}
Макросы
macro bindParams(ps: SqlPrepared; params: varargs[untyped]): untyped
Шаблоны
template dbBindParamError(paramIdx: int; val: varargs[untyped])
- Вызывает исключение
DbError. template exec(db: DbConn; stmtName: SqlPrepared; args: varargs[typed]): untyped
© 2006–2024 Andreas Rumpf
Licensed under the MIT License.
https://nim-lang.org/docs/db_sqlite.html