Compare commits
36 Commits
Author | SHA1 | Date | |
---|---|---|---|
9d1cc4bbec | |||
af44d48df1 | |||
2030fd4490 | |||
0599d41061 | |||
fb74d84cb7 | |||
fbd20de71f | |||
540d0d2f67 | |||
a05555ee67 | |||
454fc8c47a | |||
004e3c19bb | |||
4e0a173c76 | |||
bd5d8c98b8 | |||
7d45346bb6 | |||
a3dbb0bbbc | |||
9bf3c4f3ec | |||
1d7c955805 | |||
9625ac6a5e | |||
d4540a1de7 | |||
3e19b3628d | |||
8aad3cdb79 | |||
f7791b6f60 | |||
279d9aa7fd | |||
d90372127b | |||
2b78727356 | |||
445c86f97e | |||
126167fdaf | |||
ff0c5e5305 | |||
bdd62cad66 | |||
b496b10578 | |||
c6430baa9a | |||
cd52c9860d | |||
af755a8a8d | |||
1f57e0dccc | |||
61e06842af | |||
934bb26cf3 | |||
126c4f1c7c |
10
Makefile
Normal file
10
Makefile
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
SOURCES=$(shell find src -type f)
|
||||||
|
|
||||||
|
build: $(shell find src -type f)
|
||||||
|
nimble build
|
||||||
|
|
||||||
|
docs: $(shell find src -type f)
|
||||||
|
nim doc --project --index:on --git.url:https://github.com/jdbernard/fiber-orm --outdir:docs src/fiber_orm
|
||||||
|
nim rst2html --outdir:docs README.rst
|
||||||
|
cp docs/fiber_orm.html docs/index.html
|
||||||
|
.PHONY: docs
|
277
README.rst
Normal file
277
README.rst
Normal file
@ -0,0 +1,277 @@
|
|||||||
|
Fiber ORM
|
||||||
|
~~~~~~~~~
|
||||||
|
|
||||||
|
Lightweight ORM supporting the `Postgres`_ and `SQLite`_ databases in Nim.
|
||||||
|
It supports a simple, opinionated model mapper to generate SQL queries based
|
||||||
|
on Nim objects. It also includes a simple connection pooling implementation.
|
||||||
|
|
||||||
|
Fiber ORM is not intended to be a 100% all-cases-covered ORM that handles
|
||||||
|
every potential data access pattern one might wish to implement. It is best
|
||||||
|
thought of as a collection of common SQL generation patterns. It is intended
|
||||||
|
to cover 90% of the common queries and functions one might write when
|
||||||
|
implementing an SQL-based access layer. It is expected that there may be a
|
||||||
|
few more complicated queries that need to be implemented to handle specific
|
||||||
|
access patterns.
|
||||||
|
|
||||||
|
The simple mapping pattern provided by Fiber ORM also works well on top of
|
||||||
|
databases that encapsulate data access logic in SQL with, for example,
|
||||||
|
views.
|
||||||
|
|
||||||
|
.. _Postgres: https://nim-lang.org/docs/db_postgres.html
|
||||||
|
.. _SQLite: https://nim-lang.org/docs/db_sqlite.html
|
||||||
|
|
||||||
|
Basic Usage
|
||||||
|
===========
|
||||||
|
|
||||||
|
Consider a simple TODO list application that keeps track of TODO items as
|
||||||
|
well as time logged against those items.
|
||||||
|
|
||||||
|
Example DB Schema
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
You might have a schema such as:
|
||||||
|
|
||||||
|
.. code-block:: SQL
|
||||||
|
create extension if not exists "pgcrypto";
|
||||||
|
|
||||||
|
create table todo_items columns (
|
||||||
|
id uuid not null primary key default gen_random_uuid(),
|
||||||
|
owner varchar not null,
|
||||||
|
summary varchar not null,
|
||||||
|
details varchar default null,
|
||||||
|
priority integer not null default 0,
|
||||||
|
related_todo_item_ids uuid[] not null default '{}'
|
||||||
|
);
|
||||||
|
|
||||||
|
create table time_entries columns (
|
||||||
|
id uuid not null primary key default gen_random_uuid(),
|
||||||
|
todo_item_id uuid not null references todo_items (id) on delete cascade,
|
||||||
|
start timestamp with timezone not null default current_timestamp,
|
||||||
|
stop timestamp with timezone default null,
|
||||||
|
);
|
||||||
|
|
||||||
|
Example Model Definitions
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
Models may be defined as:
|
||||||
|
|
||||||
|
.. code-block:: Nim
|
||||||
|
# models.nim
|
||||||
|
import std/[options, times]
|
||||||
|
import uuids
|
||||||
|
|
||||||
|
type
|
||||||
|
TodoItem* = object
|
||||||
|
id*: UUID
|
||||||
|
owner*: string
|
||||||
|
summary*: string
|
||||||
|
details*: Option[string]
|
||||||
|
priority*: int
|
||||||
|
relatedTodoItemIds*: seq[UUID]
|
||||||
|
|
||||||
|
TimeEntry* = object
|
||||||
|
id*: UUID
|
||||||
|
todoItemId*: Option[UUID]
|
||||||
|
start*: DateTime
|
||||||
|
stop*: Option[DateTime]
|
||||||
|
|
||||||
|
Example Fiber ORM Usage
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
Using Fiber ORM we can generate a data access layer with:
|
||||||
|
|
||||||
|
.. code-block:: Nim
|
||||||
|
# db.nim
|
||||||
|
import std/[options]
|
||||||
|
import db_connectors/db_postgres
|
||||||
|
import fiber_orm
|
||||||
|
import ./models.nim
|
||||||
|
|
||||||
|
type TodoDB* = DbConnPool
|
||||||
|
|
||||||
|
proc initDb*(connString: string): TodoDB =
|
||||||
|
result = fiber_orm.initPool(
|
||||||
|
connect = proc(): DbConn = open("", "", "", connString),
|
||||||
|
poolSize = 20,
|
||||||
|
hardCap = false)
|
||||||
|
|
||||||
|
|
||||||
|
generateProcsForModels(TodoDB, [TodoItem, TimeEntry])
|
||||||
|
|
||||||
|
generateLookup(TodoDB, TimeEntry, @["todoItemId"])
|
||||||
|
|
||||||
|
This will generate the following procedures:
|
||||||
|
|
||||||
|
.. code-block:: Nim
|
||||||
|
proc getTodoItem*(db: TodoDB, id: UUID): TodoItem;
|
||||||
|
proc getTodoItemIfItExists*(db: TodoDB, id: UUID): Option[TodoItem];
|
||||||
|
proc getAllTodoItems*(db: TodoDB): seq[TodoItem];
|
||||||
|
proc createTodoItem*(db: TodoDB, rec: TodoItem): TodoItem;
|
||||||
|
proc updateTodoItem*(db: TodoDB, rec: TodoItem): bool;
|
||||||
|
proc deleteTodoItem*(db: TodoDB, rec: TodoItem): bool;
|
||||||
|
proc deleteTodoItem*(db: TodoDB, id: UUID): bool;
|
||||||
|
|
||||||
|
proc findTodoItemsWhere*(db: TodoDB, whereClause: string,
|
||||||
|
values: varargs[string, dbFormat]): seq[TodoItem];
|
||||||
|
|
||||||
|
proc getTimeEntry*(db: TodoDB, id: UUID): TimeEntry;
|
||||||
|
proc getTimeEntryIfItExists*(db: TodoDB, id: UUID): Option[TimeEntry];
|
||||||
|
proc getAllTimeEntries*(db: TodoDB): seq[TimeEntry];
|
||||||
|
proc createTimeEntry*(db: TodoDB, rec: TimeEntry): TimeEntry;
|
||||||
|
proc updateTimeEntry*(db: TodoDB, rec: TimeEntry): bool;
|
||||||
|
proc deleteTimeEntry*(db: TodoDB, rec: TimeEntry): bool;
|
||||||
|
proc deleteTimeEntry*(db: TodoDB, id: UUID): bool;
|
||||||
|
|
||||||
|
proc findTimeEntriesWhere*(db: TodoDB, whereClause: string,
|
||||||
|
values: varargs[string, dbFormat]): seq[TimeEntry];
|
||||||
|
|
||||||
|
proc findTimeEntriesByTodoItemId(db: TodoDB, todoItemId: UUID): seq[TimeEntry];
|
||||||
|
|
||||||
|
Object-Relational Modeling
|
||||||
|
==========================
|
||||||
|
|
||||||
|
Model Class
|
||||||
|
-----------
|
||||||
|
|
||||||
|
Fiber ORM uses simple Nim `object`s and `ref object`s as model classes.
|
||||||
|
Fiber ORM expects there to be one table for each model class.
|
||||||
|
|
||||||
|
Name Mapping
|
||||||
|
````````````
|
||||||
|
Fiber ORM uses `snake_case` for database identifiers (column names, table
|
||||||
|
names, etc.) and `camelCase` for Nim identifiers. We automatically convert
|
||||||
|
model names to and from table names (`TodoItem` <-> `todo_items`), as well
|
||||||
|
as column names (`userId` <-> `user_id`).
|
||||||
|
|
||||||
|
Notice that table names are automatically pluralized from model class names.
|
||||||
|
In the above example, you have:
|
||||||
|
|
||||||
|
=========== ================
|
||||||
|
Model Class Table Name
|
||||||
|
=========== ================
|
||||||
|
TodoItem todo_items
|
||||||
|
TimeEntry time_entries
|
||||||
|
=========== ================
|
||||||
|
|
||||||
|
Because Nim is style-insensitive, you can generall refer to model classes
|
||||||
|
and fields using `snake_case`, `camelCase`, or `PascalCase` in your code and
|
||||||
|
expect Fiber ORM to be able to map the names to DB identifier names properly
|
||||||
|
(though FiberORM will always use `camelCase` internally).
|
||||||
|
|
||||||
|
See the `identNameToDb`_, `dbNameToIdent`_, `tableName`_ and `dbFormat`_
|
||||||
|
procedures in the `fiber_orm/util`_ module for details.
|
||||||
|
|
||||||
|
.. _identNameToDb: fiber_orm/util.html#identNameToDb,string
|
||||||
|
.. _dbNameToIdent: fiber_orm/util.html#dbNameToIdent,string
|
||||||
|
.. _tableName: fiber_orm/util.html#tableName,type
|
||||||
|
.. _dbFormat: fiber_orm/util.html#dbFormat,DateTime
|
||||||
|
.. _util: fiber_orm/util.html
|
||||||
|
|
||||||
|
ID Field
|
||||||
|
````````
|
||||||
|
|
||||||
|
Fiber ORM expects every model class to have a field named `id`, with a
|
||||||
|
corresponding `id` column in the model table. This field must be either a
|
||||||
|
`string`, `integer`, or `UUID`_.
|
||||||
|
|
||||||
|
When creating a new record the `id` field will be omitted if it is empty
|
||||||
|
(`Option.isNone`_, `UUID.isZero`_, value of `0`, or only whitespace). This
|
||||||
|
is intended to allow for cases like the example where the database may
|
||||||
|
generate an ID when a new record is inserted. If a non-zero value is
|
||||||
|
provided, the create call will include the `id` field in the `INSERT` query.
|
||||||
|
|
||||||
|
For example, to allow the database to create the id:
|
||||||
|
|
||||||
|
.. code-block:: Nim
|
||||||
|
let item = TodoItem(
|
||||||
|
owner: "John Mann",
|
||||||
|
summary: "Create a grocery list.",
|
||||||
|
details: none[string](),
|
||||||
|
priority: 0,
|
||||||
|
relatedTodoItemIds: @[])
|
||||||
|
|
||||||
|
let itemWithId = db.createTodoItem(item)
|
||||||
|
echo $itemWithId.id # generated in the database
|
||||||
|
|
||||||
|
And to create it in code:
|
||||||
|
|
||||||
|
.. code-block:: Nim
|
||||||
|
import uuids
|
||||||
|
|
||||||
|
let item = TodoItem(
|
||||||
|
id: genUUID(),
|
||||||
|
owner: "John Mann",
|
||||||
|
summary: "Create a grocery list.",
|
||||||
|
details: none[string](),
|
||||||
|
priority: 0,
|
||||||
|
relatedTodoItemIds: @[])
|
||||||
|
|
||||||
|
let itemInDb = db.createTodoItem(item)
|
||||||
|
echo $itemInDb.id # will be the same as what was provided
|
||||||
|
|
||||||
|
.. _Option.isNone: https://nim-lang.org/docs/options.html#isNone,Option[T]
|
||||||
|
.. _UUID.isZero: https://github.com/pragmagic/uuids/blob/8cb8720b567c6bcb261bd1c0f7491bdb5209ad06/uuids.nim#L72
|
||||||
|
|
||||||
|
Supported Data Types
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
The following Nim data types are supported by Fiber ORM:
|
||||||
|
|
||||||
|
=============== ====================== =================
|
||||||
|
Nim Type Postgres Type SQLite Type
|
||||||
|
=============== ====================== =================
|
||||||
|
`string` `varchar`_
|
||||||
|
`int` `integer`_
|
||||||
|
`float` `double`_
|
||||||
|
`bool` `boolean`_
|
||||||
|
`DateTime`_ `timestamp`_
|
||||||
|
`seq[]` `array`_
|
||||||
|
`UUID`_ `uuid (pg)`_
|
||||||
|
`Option`_ *allows* `NULL` [#f1]_
|
||||||
|
`JsonNode`_ `jsonb`_
|
||||||
|
=============== ====================== =================
|
||||||
|
|
||||||
|
.. [#f1] Note that this implies that all `NULL`-able fields should be typed
|
||||||
|
as optional using `Option[fieldType]`. Conversely, any fields with
|
||||||
|
non-optional types should also be constrained to be `NOT NULL` in
|
||||||
|
the database schema.
|
||||||
|
|
||||||
|
.. _DateTime: https://nim-lang.org/docs/times.html#DateTime
|
||||||
|
.. _UUID: https://github.com/pragmagic/uuids
|
||||||
|
.. _Option: https://nim-lang.org/docs/options.html#Option
|
||||||
|
.. _JsonNode: https://nim-lang.org/docs/json.html#JsonNode
|
||||||
|
|
||||||
|
.. _varchar: https://www.postgresql.org/docs/current/datatype-character.html
|
||||||
|
.. _integer: https://www.postgresql.org/docs/current/datatype-numeric.html#DATATYPE-INT
|
||||||
|
.. _double: https://www.postgresql.org/docs/current/datatype-numeric.html#DATATYPE-FLOAT
|
||||||
|
.. _boolean: https://www.postgresql.org/docs/current/datatype-boolean.html
|
||||||
|
.. _timestamp: https://www.postgresql.org/docs/current/datatype-datetime.html
|
||||||
|
.. _array: https://www.postgresql.org/docs/current/arrays.html
|
||||||
|
.. _uuid (pg): https://www.postgresql.org/docs/current/datatype-uuid.html
|
||||||
|
.. _jsonb: https://www.postgresql.org/docs/current/datatype-json.html
|
||||||
|
|
||||||
|
Database Object
|
||||||
|
===============
|
||||||
|
|
||||||
|
Many of the Fiber ORM macros expect a database object type to be passed.
|
||||||
|
In the example above the `pool.DbConnPool`_ object is used as database
|
||||||
|
object type (aliased as `TodoDB`). This is the intended usage pattern, but
|
||||||
|
anything can be passed as the database object type so long as there is a
|
||||||
|
defined `withConn` template that provides an injected `conn: DbConn` object
|
||||||
|
to the provided statement body.
|
||||||
|
|
||||||
|
For example, a valid database object implementation that opens a new
|
||||||
|
connection for every request might look like this:
|
||||||
|
|
||||||
|
.. code-block:: Nim
|
||||||
|
import std/db_postgres
|
||||||
|
|
||||||
|
type TodoDB* = object
|
||||||
|
connString: string
|
||||||
|
|
||||||
|
template withConn*(db: TodoDB, stmt: untyped): untyped =
|
||||||
|
let conn {.inject.} = open("", "", "", db.connString)
|
||||||
|
try: stmt
|
||||||
|
finally: close(conn)
|
||||||
|
|
||||||
|
.. _pool.DbConnPool: fiber_orm/pool.html#DbConnPool
|
202
docs/README.html
Normal file
202
docs/README.html
Normal file
@ -0,0 +1,202 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
||||||
|
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||||
|
<!-- This file is generated by Nim. -->
|
||||||
|
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||||
|
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
|
||||||
|
<!-- Favicon -->
|
||||||
|
<link rel="shortcut icon" href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAUAAAAF////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAIAAABbAAAAlQAAAKIAAACbAAAAmwAAAKIAAACVAAAAWwAAAAL///8A////AP///wD///8A////AAAAABQAAADAAAAAYwAAAA3///8A////AP///wD///8AAAAADQAAAGMAAADAAAAAFP///wD///8A////AP///wAAAACdAAAAOv///wD///8A////AP///wD///8A////AP///wD///8AAAAAOgAAAJ3///8A////AP///wAAAAAnAAAAcP///wAAAAAoAAAASv///wD///8A////AP///wAAAABKAAAAKP///wAAAABwAAAAJ////wD///8AAAAAgQAAABwAAACIAAAAkAAAAJMAAACtAAAAFQAAABUAAACtAAAAkwAAAJAAAACIAAAAHAAAAIH///8A////AAAAAKQAAACrAAAAaP///wD///8AAAAARQAAANIAAADSAAAARf///wD///8AAAAAaAAAAKsAAACk////AAAAADMAAACcAAAAnQAAABj///8A////AP///wAAAAAYAAAAGP///wD///8A////AAAAABgAAACdAAAAnAAAADMAAAB1AAAAwwAAAP8AAADpAAAAsQAAAE4AAAAb////AP///wAAAAAbAAAATgAAALEAAADpAAAA/wAAAMMAAAB1AAAAtwAAAOkAAAD/AAAA/wAAAP8AAADvAAAA3gAAAN4AAADeAAAA3gAAAO8AAAD/AAAA/wAAAP8AAADpAAAAtwAAAGUAAAA/AAAA3wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAADfAAAAPwAAAGX///8A////AAAAAEgAAADtAAAAvwAAAL0AAADGAAAA7wAAAO8AAADGAAAAvQAAAL8AAADtAAAASP///wD///8A////AP///wD///8AAAAAO////wD///8A////AAAAAIcAAACH////AP///wD///8AAAAAO////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A//8AAP//AAD4HwAA7/cAAN/7AAD//wAAoYUAAJ55AACf+QAAh+EAAAAAAADAAwAA4AcAAP5/AAD//wAA//8AAA=="/>
|
||||||
|
<link rel="icon" type="image/png" sizes="32x32" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAA3XAAAN1wFCKJt4AAAAB3RJTUUH4QQQEwksSS9ZWwAAAk1JREFUWMPtll2ITVEUx39nn/O7Y5qR8f05wtCUUr6ZIS++8pEnkZInPImneaCQ5METNdOkeFBKUhMPRIkHKfEuUZSUlGlKPN2TrgfncpvmnntnmlEyq1Z7t89/rf9a6+y99oZxGZf/XeIq61EdtgKXgdXA0xrYAvBjOIF1AI9zvjcC74BSpndrJPkBWDScTF8Aa4E3wDlgHbASaANmVqlcCnwHvgDvgVfAJ+AikAAvgfVZwLnSVZHZaOuKoQi3ZOMi4NkYkpe1p4J7A8BpYAD49hfIy/oqG0+hLomiKP2L5L+1ubn5115S+3OAn4EnwBlgMzCjyt6ZAnQCJ4A7wOs88iRJHvw50HoujuPBoCKwHWiosy8MdfZnAdcHk8dxXFJ3VQbQlCTJvRBCGdRbD4M6uc5glpY3eAihpN5S5w12diSEcCCEcKUO4ljdr15T76ur1FDDLIQQ3qv71EdDOe3Kxj3leRXyk+pxdWnFWod6Wt2bY3de3aSuUHcPBVimHs7mK9WrmeOF6lR1o9qnzskh2ar2qm1qizpfXaPeVGdlmGN5pb09qMxz1Xb1kLqgzn1RyH7JUXW52lr5e/Kqi9qpto7V1atuUzfnARrV7jEib1T76gG2qxdGmXyiekkt1GswPTtek0aBfJp6YySGBfWg2tPQ0FAYgf1stUfdmdcjarbYJEniKIq6gY/Aw+zWHAC+p2labGpqiorFYgGYCEzN7oQdQClN07O1/EfDyGgC0ALMBdYAi4FyK+4H3gLPsxfR1zRNi+NP7nH5J+QntnXe5B5mpfQAAAAASUVORK5CYII=">
|
||||||
|
|
||||||
|
<!-- Google fonts -->
|
||||||
|
<link href='https://fonts.googleapis.com/css?family=Lato:400,600,900' rel='stylesheet' type='text/css'/>
|
||||||
|
<link href='https://fonts.googleapis.com/css?family=Source+Code+Pro:400,500,600' rel='stylesheet' type='text/css'/>
|
||||||
|
|
||||||
|
<!-- CSS -->
|
||||||
|
<title>README</title>
|
||||||
|
<link rel="stylesheet" type="text/css" href="nimdoc.out.css">
|
||||||
|
|
||||||
|
<script type="text/javascript" src="dochack.js"></script>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
function main() {
|
||||||
|
var pragmaDots = document.getElementsByClassName("pragmadots");
|
||||||
|
for (var i = 0; i < pragmaDots.length; i++) {
|
||||||
|
pragmaDots[i].onclick = function(event) {
|
||||||
|
// Hide tease
|
||||||
|
event.target.parentNode.style.display = "none";
|
||||||
|
// Show actual
|
||||||
|
event.target.parentNode.nextElementSibling.style.display = "inline";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function switchTheme(e) {
|
||||||
|
if (e.target.checked) {
|
||||||
|
document.documentElement.setAttribute('data-theme', 'dark');
|
||||||
|
localStorage.setItem('theme', 'dark');
|
||||||
|
} else {
|
||||||
|
document.documentElement.setAttribute('data-theme', 'light');
|
||||||
|
localStorage.setItem('theme', 'light');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const toggleSwitch = document.querySelector('.theme-switch input[type="checkbox"]');
|
||||||
|
if (toggleSwitch !== null) {
|
||||||
|
toggleSwitch.addEventListener('change', switchTheme, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
var currentTheme = localStorage.getItem('theme');
|
||||||
|
if (!currentTheme && window.matchMedia('(prefers-color-scheme: dark)').matches) {
|
||||||
|
currentTheme = 'dark';
|
||||||
|
}
|
||||||
|
if (currentTheme) {
|
||||||
|
document.documentElement.setAttribute('data-theme', currentTheme);
|
||||||
|
|
||||||
|
if (currentTheme === 'dark' && toggleSwitch !== null) {
|
||||||
|
toggleSwitch.checked = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener('DOMContentLoaded', main);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="document" id="documentId">
|
||||||
|
<div class="container">
|
||||||
|
<h1 class="title">README</h1>
|
||||||
|
|
||||||
|
<h1 id="fiber-orm">Fiber ORM</h1><p>Lightweight ORM supporting the <a class="reference external" href="https://nim-lang.org/docs/db_postgres.html">Postgres</a> and <a class="reference external" href="https://nim-lang.org/docs/db_sqlite.html">SQLite</a> databases in Nim. It supports a simple, opinionated model mapper to generate SQL queries based on Nim objects. It also includes a simple connection pooling implementation.</p>
|
||||||
|
<p>Fiber ORM is not intended to be a 100% all-cases-covered ORM that handles every potential data access pattern one might wish to implement. It is best thought of as a collection of common SQL generation patterns. It is intended to cover 90% of the common queries and functions one might write when implementing an SQL-based access layer. It is expected that there may be a few more complicated queries that need to be implemented to handle specific access patterns.</p>
|
||||||
|
<p>The simple mapping pattern provided by Fiber ORM also works well on top of databases that encapsulate data access logic in SQL with, for example, views.</p>
|
||||||
|
|
||||||
|
<h2 id="basic-usage">Basic Usage</h2><p>Consider a simple TODO list application that keeps track of TODO items as well as time logged against those items. You might have a schema such as:</p>
|
||||||
|
<pre class="listing">create extension if not exists "pgcrypto";
|
||||||
|
|
||||||
|
create table todo_items columns (
|
||||||
|
id uuid not null primary key default gen_random_uuid(),
|
||||||
|
owner varchar not null,
|
||||||
|
summary varchar not null,
|
||||||
|
details varchar default null,
|
||||||
|
priority integer not null default 0,
|
||||||
|
related_todo_item_ids uuid[] not null default '{}'
|
||||||
|
);
|
||||||
|
|
||||||
|
create table time_entries columns (
|
||||||
|
id uuid not null primary key default gen_random_uuid(),
|
||||||
|
todo_item_id uuid not null references todo_items (id) on delete cascade,
|
||||||
|
start timestamp with timezone not null default current_timestamp,
|
||||||
|
stop timestamp with timezone default null,
|
||||||
|
);</pre><p>Models may be defined as:</p>
|
||||||
|
<pre class="listing"><span class="Comment"># models.nim</span>
|
||||||
|
<span class="Keyword">import</span> <span class="Identifier">std</span><span class="Operator">/</span><span class="Identifier">options</span><span class="Punctuation">,</span> <span class="Identifier">std</span><span class="Operator">/</span><span class="Identifier">times</span>
|
||||||
|
<span class="Keyword">import</span> <span class="Identifier">uuids</span>
|
||||||
|
|
||||||
|
<span class="Keyword">type</span>
|
||||||
|
<span class="Identifier">TodoItem</span><span class="Operator">*</span> <span class="Operator">=</span> <span class="Keyword">object</span>
|
||||||
|
<span class="Identifier">id</span><span class="Operator">*:</span> <span class="Identifier">UUID</span>
|
||||||
|
<span class="Identifier">owner</span><span class="Operator">*:</span> <span class="Identifier">string</span>
|
||||||
|
<span class="Identifier">summary</span><span class="Operator">*:</span> <span class="Identifier">string</span>
|
||||||
|
<span class="Identifier">details</span><span class="Operator">*:</span> <span class="Identifier">Option</span><span class="Punctuation">[</span><span class="Identifier">string</span><span class="Punctuation">]</span>
|
||||||
|
<span class="Identifier">priority</span><span class="Operator">*:</span> <span class="Identifier">int</span>
|
||||||
|
<span class="Identifier">relatedTodoItemIds</span><span class="Operator">*:</span> <span class="Identifier">seq</span><span class="Punctuation">[</span><span class="Identifier">UUID</span><span class="Punctuation">]</span>
|
||||||
|
|
||||||
|
<span class="Identifier">TimeEntry</span><span class="Operator">*</span> <span class="Operator">=</span> <span class="Keyword">object</span>
|
||||||
|
<span class="Identifier">id</span><span class="Operator">*:</span> <span class="Identifier">UUID</span>
|
||||||
|
<span class="Identifier">todoItemId</span><span class="Operator">*:</span> <span class="Identifier">Option</span><span class="Punctuation">[</span><span class="Identifier">UUID</span><span class="Punctuation">]</span>
|
||||||
|
<span class="Identifier">start</span><span class="Operator">*:</span> <span class="Identifier">DateTime</span>
|
||||||
|
<span class="Identifier">stop</span><span class="Operator">*:</span> <span class="Identifier">Option</span><span class="Punctuation">[</span><span class="Identifier">DateTime</span><span class="Punctuation">]</span></pre><p>Using Fiber ORM we can generate a data access layer with:</p>
|
||||||
|
<pre class="listing"><span class="Comment"># db.nim</span>
|
||||||
|
<span class="Keyword">import</span> <span class="Identifier">fiber_orm</span>
|
||||||
|
<span class="Keyword">import</span> <span class="Operator">./</span><span class="Identifier">models</span><span class="Operator">.</span><span class="Identifier">nim</span>
|
||||||
|
|
||||||
|
<span class="Keyword">type</span> <span class="Identifier">TodoDB</span><span class="Operator">*</span> <span class="Operator">=</span> <span class="Identifier">DbConnPool</span>
|
||||||
|
|
||||||
|
<span class="Keyword">proc</span> <span class="Identifier">initDb</span><span class="Operator">*</span><span class="Punctuation">(</span><span class="Identifier">connString</span><span class="Punctuation">:</span> <span class="Identifier">string</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">TodoDB</span> <span class="Operator">=</span>
|
||||||
|
<span class="Identifier">fiber_orm</span><span class="Operator">.</span><span class="Identifier">initPool</span><span class="Punctuation">(</span><span class="Identifier">connect</span> <span class="Operator">=</span>
|
||||||
|
<span class="Keyword">proc</span><span class="Punctuation">(</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">DbConn</span> <span class="Operator">=</span> <span class="Identifier">open</span><span class="Punctuation">(</span><span class="StringLit">""</span><span class="Punctuation">,</span> <span class="StringLit">""</span><span class="Punctuation">,</span> <span class="StringLit">""</span><span class="Punctuation">,</span> <span class="Identifier">connString</span><span class="Punctuation">)</span><span class="Punctuation">)</span>
|
||||||
|
|
||||||
|
<span class="Identifier">generateProcsForModels</span><span class="Punctuation">(</span><span class="Identifier">TodoDB</span><span class="Punctuation">,</span> <span class="Punctuation">[</span><span class="Identifier">TodoItem</span><span class="Punctuation">,</span> <span class="Identifier">TimeEntry</span><span class="Punctuation">]</span><span class="Punctuation">)</span>
|
||||||
|
|
||||||
|
<span class="Identifier">generateLookup</span><span class="Punctuation">(</span><span class="Identifier">TodoDB</span><span class="Punctuation">,</span> <span class="Identifier">TimeEntry</span><span class="Punctuation">,</span> <span class="Operator">@</span><span class="Punctuation">[</span><span class="StringLit">"todoItemId"</span><span class="Punctuation">]</span><span class="Punctuation">)</span></pre><p>This will generate the following procedures:</p>
|
||||||
|
<pre class="listing"><span class="Keyword">proc</span> <span class="Identifier">getTodoItem</span><span class="Operator">*</span><span class="Punctuation">(</span><span class="Identifier">db</span><span class="Punctuation">:</span> <span class="Identifier">TodoDB</span><span class="Punctuation">,</span> <span class="Identifier">id</span><span class="Punctuation">:</span> <span class="Identifier">UUID</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">TodoItem</span><span class="Punctuation">;</span>
|
||||||
|
<span class="Keyword">proc</span> <span class="Identifier">getAllTodoItems</span><span class="Operator">*</span><span class="Punctuation">(</span><span class="Identifier">db</span><span class="Punctuation">:</span> <span class="Identifier">TodoDB</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">seq</span><span class="Punctuation">[</span><span class="Identifier">TodoItem</span><span class="Punctuation">]</span><span class="Punctuation">;</span>
|
||||||
|
<span class="Keyword">proc</span> <span class="Identifier">createTodoItem</span><span class="Operator">*</span><span class="Punctuation">(</span><span class="Identifier">db</span><span class="Punctuation">:</span> <span class="Identifier">TodoDB</span><span class="Punctuation">,</span> <span class="Identifier">rec</span><span class="Punctuation">:</span> <span class="Identifier">TodoItem</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">TodoItem</span><span class="Punctuation">;</span>
|
||||||
|
<span class="Keyword">proc</span> <span class="Identifier">updateTodoItem</span><span class="Operator">*</span><span class="Punctuation">(</span><span class="Identifier">db</span><span class="Punctuation">:</span> <span class="Identifier">TodoDB</span><span class="Punctuation">,</span> <span class="Identifier">rec</span><span class="Punctuation">:</span> <span class="Identifier">TodoItem</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">bool</span><span class="Punctuation">;</span>
|
||||||
|
<span class="Keyword">proc</span> <span class="Identifier">deleteTodoItem</span><span class="Operator">*</span><span class="Punctuation">(</span><span class="Identifier">db</span><span class="Punctuation">:</span> <span class="Identifier">TodoDB</span><span class="Punctuation">,</span> <span class="Identifier">rec</span><span class="Punctuation">:</span> <span class="Identifier">TodoItem</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">bool</span><span class="Punctuation">;</span>
|
||||||
|
<span class="Keyword">proc</span> <span class="Identifier">deleteTodoItem</span><span class="Operator">*</span><span class="Punctuation">(</span><span class="Identifier">db</span><span class="Punctuation">:</span> <span class="Identifier">TodoDB</span><span class="Punctuation">,</span> <span class="Identifier">id</span><span class="Punctuation">:</span> <span class="Identifier">UUID</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">bool</span><span class="Punctuation">;</span>
|
||||||
|
|
||||||
|
<span class="Keyword">proc</span> <span class="Identifier">findTodoItemsWhere</span><span class="Operator">*</span><span class="Punctuation">(</span><span class="Identifier">db</span><span class="Punctuation">:</span> <span class="Identifier">TodoDB</span><span class="Punctuation">,</span> <span class="Identifier">whereClause</span><span class="Punctuation">:</span> <span class="Identifier">string</span><span class="Punctuation">,</span>
|
||||||
|
<span class="Identifier">values</span><span class="Punctuation">:</span> <span class="Identifier">varargs</span><span class="Punctuation">[</span><span class="Identifier">string</span><span class="Punctuation">,</span> <span class="Identifier">dbFormat</span><span class="Punctuation">]</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">seq</span><span class="Punctuation">[</span><span class="Identifier">TodoItem</span><span class="Punctuation">]</span><span class="Punctuation">;</span>
|
||||||
|
|
||||||
|
<span class="Keyword">proc</span> <span class="Identifier">getTimeEntry</span><span class="Operator">*</span><span class="Punctuation">(</span><span class="Identifier">db</span><span class="Punctuation">:</span> <span class="Identifier">TodoDB</span><span class="Punctuation">,</span> <span class="Identifier">id</span><span class="Punctuation">:</span> <span class="Identifier">UUID</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">TimeEntry</span><span class="Punctuation">;</span>
|
||||||
|
<span class="Keyword">proc</span> <span class="Identifier">getAllTimeEntries</span><span class="Operator">*</span><span class="Punctuation">(</span><span class="Identifier">db</span><span class="Punctuation">:</span> <span class="Identifier">TodoDB</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">seq</span><span class="Punctuation">[</span><span class="Identifier">TimeEntry</span><span class="Punctuation">]</span><span class="Punctuation">;</span>
|
||||||
|
<span class="Keyword">proc</span> <span class="Identifier">createTimeEntry</span><span class="Operator">*</span><span class="Punctuation">(</span><span class="Identifier">db</span><span class="Punctuation">:</span> <span class="Identifier">TodoDB</span><span class="Punctuation">,</span> <span class="Identifier">rec</span><span class="Punctuation">:</span> <span class="Identifier">TimeEntry</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">TimeEntry</span><span class="Punctuation">;</span>
|
||||||
|
<span class="Keyword">proc</span> <span class="Identifier">updateTimeEntry</span><span class="Operator">*</span><span class="Punctuation">(</span><span class="Identifier">db</span><span class="Punctuation">:</span> <span class="Identifier">TodoDB</span><span class="Punctuation">,</span> <span class="Identifier">rec</span><span class="Punctuation">:</span> <span class="Identifier">TimeEntry</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">bool</span><span class="Punctuation">;</span>
|
||||||
|
<span class="Keyword">proc</span> <span class="Identifier">deleteTimeEntry</span><span class="Operator">*</span><span class="Punctuation">(</span><span class="Identifier">db</span><span class="Punctuation">:</span> <span class="Identifier">TodoDB</span><span class="Punctuation">,</span> <span class="Identifier">rec</span><span class="Punctuation">:</span> <span class="Identifier">TimeEntry</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">bool</span><span class="Punctuation">;</span>
|
||||||
|
<span class="Keyword">proc</span> <span class="Identifier">deleteTimeEntry</span><span class="Operator">*</span><span class="Punctuation">(</span><span class="Identifier">db</span><span class="Punctuation">:</span> <span class="Identifier">TodoDB</span><span class="Punctuation">,</span> <span class="Identifier">id</span><span class="Punctuation">:</span> <span class="Identifier">UUID</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">bool</span><span class="Punctuation">;</span>
|
||||||
|
|
||||||
|
<span class="Keyword">proc</span> <span class="Identifier">findTimeEntriesWhere</span><span class="Operator">*</span><span class="Punctuation">(</span><span class="Identifier">db</span><span class="Punctuation">:</span> <span class="Identifier">TodoDB</span><span class="Punctuation">,</span> <span class="Identifier">whereClause</span><span class="Punctuation">:</span> <span class="Identifier">string</span><span class="Punctuation">,</span>
|
||||||
|
<span class="Identifier">values</span><span class="Punctuation">:</span> <span class="Identifier">varargs</span><span class="Punctuation">[</span><span class="Identifier">string</span><span class="Punctuation">,</span> <span class="Identifier">dbFormat</span><span class="Punctuation">]</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">seq</span><span class="Punctuation">[</span><span class="Identifier">TimeEntry</span><span class="Punctuation">]</span><span class="Punctuation">;</span>
|
||||||
|
|
||||||
|
<span class="Keyword">proc</span> <span class="Identifier">findTimeEntriesByTodoItemId</span><span class="Punctuation">(</span><span class="Identifier">db</span><span class="Punctuation">:</span> <span class="Identifier">TodoDB</span><span class="Punctuation">,</span> <span class="Identifier">todoItemId</span><span class="Punctuation">:</span> <span class="Identifier">UUID</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">seq</span><span class="Punctuation">[</span><span class="Identifier">TimeEntry</span><span class="Punctuation">]</span><span class="Punctuation">;</span></pre>
|
||||||
|
<h2 id="objectminusrelational-modeling">Object-Relational Modeling</h2>
|
||||||
|
<h3 id="model-class">Model Class</h3><p>Fiber ORM uses simple Nim <tt class="docutils literal"><span class="pre">object</span></tt>s and <tt class="docutils literal"><span class="pre">ref object</span></tt>s as model classes. Fiber ORM expects there to be one table for each model class.</p>
|
||||||
|
|
||||||
|
<h4 id="name-mapping">Name Mapping</h4><p>Fiber ORM uses <tt class="docutils literal"><span class="pre">snake_case</span></tt> for database identifiers (column names, table names, etc.) and <tt class="docutils literal"><span class="pre">camelCase</span></tt> for Nim identifiers. We automatically convert model names to and from table names (<tt class="docutils literal"><span class="pre">TodoItem</span></tt> <-> <tt class="docutils literal"><span class="pre">todo_items</span></tt>), as well as column names (<tt class="docutils literal"><span class="pre">userId</span></tt> <-> <tt class="docutils literal"><span class="pre">user_id</span></tt>).</p>
|
||||||
|
<p>Notice that table names are automatically pluralized from model class names. In the above example, you have:</p>
|
||||||
|
<table border="1" class="docutils"><tr><th>Model Class</th><th>Table Name</th></tr>
|
||||||
|
<tr><td>TodoItem</td><td>todo_items</td></tr>
|
||||||
|
<tr><td>TimeEntry</td><td>time_entries</td></tr>
|
||||||
|
</table><p>Because Nim is style-insensitive, you can generall refer to model classes and fields using <tt class="docutils literal"><span class="pre">snake_case</span></tt>, <tt class="docutils literal"><span class="pre">camelCase</span></tt>, or <tt class="docutils literal"><span class="pre">PascalCase</span></tt> in your code and expect Fiber ORM to be able to map the names to DB identifier names properly (though FiberORM will always use <tt class="docutils literal"><span class="pre">camelCase</span></tt> internally).</p>
|
||||||
|
<p>See the <a class="reference external" href="fiber_orm/util.html#identNameToDb,string">identNameToDb</a>, <a class="reference external" href="fiber_orm/util.html#dbNameToIdent,string">dbNameToIdent</a>, <a class="reference external" href="fiber_orm/util.html#tableName,type">tableName</a> and <a class="reference external" href="fiber_orm/util.html#dbFormat,DateTime">dbFormat</a> procedures in the <a class="reference internal" href="#fiber">fiber</a> module for details.</p>
|
||||||
|
|
||||||
|
<h4 id="id-field">ID Field</h4><p>Fiber ORM expects every model class to have a field named <tt class="docutils literal"><span class="pre">id</span></tt>, with a corresponding <tt class="docutils literal"><span class="pre">id</span></tt> column in the model table. This field must be either a <tt class="docutils literal"><span class="pre">string</span></tt>, <tt class="docutils literal"><span class="pre">integer</span></tt>, or <a class="reference external" href="https://github.com/pragmagic/uuids">UUID</a>.</p>
|
||||||
|
<p>When creating a new record the <tt class="docutils literal"><span class="pre">id</span></tt> field will be omitted if it is empty (<a class="reference external" href="https://nim-lang.org/docs/options.html#isNone,Option[T]">Option.isNone</a>, <a class="reference external" href="https://github.com/pragmagic/uuids/blob/8cb8720b567c6bcb261bd1c0f7491bdb5209ad06/uuids.nim#L72">UUID.isZero</a>, value of <tt class="docutils literal"><span class="pre">0</span></tt>, or only whitespace). This is intended to allow for cases like the example where the database may generate an ID when a new record is inserted. If a non-zero value is provided, the create call will include the <tt class="docutils literal"><span class="pre">id</span></tt> field in the <tt class="docutils literal"><span class="pre">INSERT</span></tt> query.</p>
|
||||||
|
|
||||||
|
<h3 id="supported-data-types">Supported Data Types</h3><p>The following Nim data types are supported by Fiber ORM:</p>
|
||||||
|
<table border="1" class="docutils"><tr><th>Nim Type</th><th>Postgres Type</th><th>SQLite Type</th></tr>
|
||||||
|
<tr><td><tt class="docutils literal"><span class="pre">string</span></tt></td><td><a class="reference external" href="https://www.postgresql.org/docs/current/datatype-character.html">varchar</a></td><td></td></tr>
|
||||||
|
<tr><td><tt class="docutils literal"><span class="pre">int</span></tt></td><td><a class="reference external" href="https://www.postgresql.org/docs/current/datatype-numeric.html#DATATYPE-INT">integer</a></td><td></td></tr>
|
||||||
|
<tr><td><tt class="docutils literal"><span class="pre">float</span></tt></td><td><a class="reference external" href="https://www.postgresql.org/docs/current/datatype-numeric.html#DATATYPE-FLOAT">double</a></td><td></td></tr>
|
||||||
|
<tr><td><tt class="docutils literal"><span class="pre">bool</span></tt></td><td><a class="reference external" href="https://www.postgresql.org/docs/current/datatype-boolean.html">boolean</a></td><td></td></tr>
|
||||||
|
<tr><td><a class="reference external" href="https://nim-lang.org/docs/times.html#DateTime">DateTime</a></td><td><a class="reference external" href="https://www.postgresql.org/docs/current/datatype-datetime.html">timestamp</a></td><td></td></tr>
|
||||||
|
<tr><td><tt class="docutils literal"><span class="pre">seq[]</span></tt></td><td><a class="reference external" href="https://www.postgresql.org/docs/current/arrays.html">array</a></td><td></td></tr>
|
||||||
|
<tr><td><a class="reference external" href="https://github.com/pragmagic/uuids">UUID</a></td><td><a class="reference external" href="https://www.postgresql.org/docs/current/datatype-uuid.html">uuid (pg)</a></td><td></td></tr>
|
||||||
|
<tr><td><a class="reference external" href="https://nim-lang.org/docs/options.html#Option">Option</a></td><td><em>allows</em> <tt class="docutils literal"><span class="pre">NULL</span></tt> <sup><strong><a class="reference internal" href="#footnote-f1">[1]</a></strong></sup></td><td></td></tr>
|
||||||
|
<tr><td><a class="reference external" href="https://nim-lang.org/docs/json.html#JsonNode">JsonNode</a></td><td><a class="reference external" href="https://www.postgresql.org/docs/current/datatype-json.html">jsonb</a></td><td></td></tr>
|
||||||
|
</table><hr class="footnote"><div class="footnote-group">
|
||||||
|
<div id="footnote-f1"><div class="footnote-label"><sup><strong><a href="#footnote-f1">[1]</a></strong></sup></div>   Note that this implies that all <tt class="docutils literal"><span class="pre">NULL</span></tt>-able fields should be typed as optional using <tt class="docutils literal"><span class="pre">Option[fieldType]</span></tt>. Conversely, any fields with non-optional types should also be constrained to be <tt class="docutils literal"><span class="pre">NOT NULL</span></tt> in the database schema.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h2 id="database-object">Database Object</h2><p>Many of the Fiber ORM macros expect a database object type to be passed. In the example above the <a class="reference internal" href="#fiber">fiber</a> object is used as database object type (aliased as <tt class="docutils literal"><span class="pre">TodoDB</span></tt>). This is the intended usage pattern, but anything can be passed as the database object type so long as there is a defined <tt class="docutils literal"><span class="pre">withConn</span></tt> template that provides an injected <tt class="docutils literal"><span class="pre">conn: DbConn</span></tt> object to the provided statement body.</p>
|
||||||
|
<p>For example, a valid database object implementation that opens a new connection for every request might look like this:</p>
|
||||||
|
<pre class="listing"><span class="Keyword">import</span> <span class="Identifier">std</span><span class="Operator">/</span><span class="Identifier">db_postgres</span>
|
||||||
|
|
||||||
|
<span class="Keyword">type</span> <span class="Identifier">TodoDB</span><span class="Operator">*</span> <span class="Operator">=</span> <span class="Keyword">object</span>
|
||||||
|
<span class="Identifier">connString</span><span class="Punctuation">:</span> <span class="Identifier">string</span>
|
||||||
|
|
||||||
|
<span class="Keyword">template</span> <span class="Identifier">withConn</span><span class="Operator">*</span><span class="Punctuation">(</span><span class="Identifier">db</span><span class="Punctuation">:</span> <span class="Identifier">TodoDB</span><span class="Punctuation">,</span> <span class="Identifier">stmt</span><span class="Punctuation">:</span> <span class="Identifier">untyped</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">untyped</span> <span class="Operator">=</span>
|
||||||
|
<span class="Keyword">let</span> <span class="Identifier">conn</span> <span class="Punctuation">{</span><span class="Operator">.</span><span class="Identifier">inject</span><span class="Operator">.</span><span class="Punctuation">}</span> <span class="Operator">=</span> <span class="Identifier">open</span><span class="Punctuation">(</span><span class="StringLit">""</span><span class="Punctuation">,</span> <span class="StringLit">""</span><span class="Punctuation">,</span> <span class="StringLit">""</span><span class="Punctuation">,</span> <span class="Identifier">db</span><span class="Operator">.</span><span class="Identifier">connString</span><span class="Punctuation">)</span>
|
||||||
|
<span class="Keyword">try</span><span class="Punctuation">:</span> <span class="Identifier">stmt</span>
|
||||||
|
<span class="Keyword">finally</span><span class="Punctuation">:</span> <span class="Identifier">close</span><span class="Punctuation">(</span><span class="Identifier">conn</span><span class="Punctuation">)</span></pre>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="twelve-columns footer">
|
||||||
|
<span class="nim-sprite"></span>
|
||||||
|
<br/>
|
||||||
|
<small style="color: var(--hint);">Made with Nim. Generated: 2022-09-04 02:31:20 UTC</small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
2041
docs/dochack.js
Normal file
2041
docs/dochack.js
Normal file
File diff suppressed because it is too large
Load Diff
619
docs/fiber_orm.html
Normal file
619
docs/fiber_orm.html
Normal file
@ -0,0 +1,619 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
||||||
|
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||||
|
<!-- This file is generated by Nim. -->
|
||||||
|
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||||
|
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
|
||||||
|
<!-- Favicon -->
|
||||||
|
<link rel="shortcut icon" href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAUAAAAF////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAIAAABbAAAAlQAAAKIAAACbAAAAmwAAAKIAAACVAAAAWwAAAAL///8A////AP///wD///8A////AAAAABQAAADAAAAAYwAAAA3///8A////AP///wD///8AAAAADQAAAGMAAADAAAAAFP///wD///8A////AP///wAAAACdAAAAOv///wD///8A////AP///wD///8A////AP///wD///8AAAAAOgAAAJ3///8A////AP///wAAAAAnAAAAcP///wAAAAAoAAAASv///wD///8A////AP///wAAAABKAAAAKP///wAAAABwAAAAJ////wD///8AAAAAgQAAABwAAACIAAAAkAAAAJMAAACtAAAAFQAAABUAAACtAAAAkwAAAJAAAACIAAAAHAAAAIH///8A////AAAAAKQAAACrAAAAaP///wD///8AAAAARQAAANIAAADSAAAARf///wD///8AAAAAaAAAAKsAAACk////AAAAADMAAACcAAAAnQAAABj///8A////AP///wAAAAAYAAAAGP///wD///8A////AAAAABgAAACdAAAAnAAAADMAAAB1AAAAwwAAAP8AAADpAAAAsQAAAE4AAAAb////AP///wAAAAAbAAAATgAAALEAAADpAAAA/wAAAMMAAAB1AAAAtwAAAOkAAAD/AAAA/wAAAP8AAADvAAAA3gAAAN4AAADeAAAA3gAAAO8AAAD/AAAA/wAAAP8AAADpAAAAtwAAAGUAAAA/AAAA3wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAADfAAAAPwAAAGX///8A////AAAAAEgAAADtAAAAvwAAAL0AAADGAAAA7wAAAO8AAADGAAAAvQAAAL8AAADtAAAASP///wD///8A////AP///wD///8AAAAAO////wD///8A////AAAAAIcAAACH////AP///wD///8AAAAAO////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A//8AAP//AAD4HwAA7/cAAN/7AAD//wAAoYUAAJ55AACf+QAAh+EAAAAAAADAAwAA4AcAAP5/AAD//wAA//8AAA=="/>
|
||||||
|
<link rel="icon" type="image/png" sizes="32x32" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAA3XAAAN1wFCKJt4AAAAB3RJTUUH4QQQEwksSS9ZWwAAAk1JREFUWMPtll2ITVEUx39nn/O7Y5qR8f05wtCUUr6ZIS++8pEnkZInPImneaCQ5METNdOkeFBKUhMPRIkHKfEuUZSUlGlKPN2TrgfncpvmnntnmlEyq1Z7t89/rf9a6+y99oZxGZf/XeIq61EdtgKXgdXA0xrYAvBjOIF1AI9zvjcC74BSpndrJPkBWDScTF8Aa4E3wDlgHbASaANmVqlcCnwHvgDvgVfAJ+AikAAvgfVZwLnSVZHZaOuKoQi3ZOMi4NkYkpe1p4J7A8BpYAD49hfIy/oqG0+hLomiKP2L5L+1ubn5115S+3OAn4EnwBlgMzCjyt6ZAnQCJ4A7wOs88iRJHvw50HoujuPBoCKwHWiosy8MdfZnAdcHk8dxXFJ3VQbQlCTJvRBCGdRbD4M6uc5glpY3eAihpN5S5w12diSEcCCEcKUO4ljdr15T76ur1FDDLIQQ3qv71EdDOe3Kxj3leRXyk+pxdWnFWod6Wt2bY3de3aSuUHcPBVimHs7mK9WrmeOF6lR1o9qnzskh2ar2qm1qizpfXaPeVGdlmGN5pb09qMxz1Xb1kLqgzn1RyH7JUXW52lr5e/Kqi9qpto7V1atuUzfnARrV7jEib1T76gG2qxdGmXyiekkt1GswPTtek0aBfJp6YySGBfWg2tPQ0FAYgf1stUfdmdcjarbYJEniKIq6gY/Aw+zWHAC+p2labGpqiorFYgGYCEzN7oQdQClN07O1/EfDyGgC0ALMBdYAi4FyK+4H3gLPsxfR1zRNi+NP7nH5J+QntnXe5B5mpfQAAAAASUVORK5CYII=">
|
||||||
|
|
||||||
|
<!-- Google fonts -->
|
||||||
|
<link href='https://fonts.googleapis.com/css?family=Lato:400,600,900' rel='stylesheet' type='text/css'/>
|
||||||
|
<link href='https://fonts.googleapis.com/css?family=Source+Code+Pro:400,500,600' rel='stylesheet' type='text/css'/>
|
||||||
|
|
||||||
|
<!-- CSS -->
|
||||||
|
<title>src/fiber_orm</title>
|
||||||
|
<link rel="stylesheet" type="text/css" href="nimdoc.out.css">
|
||||||
|
|
||||||
|
<script type="text/javascript" src="dochack.js"></script>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
function main() {
|
||||||
|
var pragmaDots = document.getElementsByClassName("pragmadots");
|
||||||
|
for (var i = 0; i < pragmaDots.length; i++) {
|
||||||
|
pragmaDots[i].onclick = function(event) {
|
||||||
|
// Hide tease
|
||||||
|
event.target.parentNode.style.display = "none";
|
||||||
|
// Show actual
|
||||||
|
event.target.parentNode.nextElementSibling.style.display = "inline";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function switchTheme(e) {
|
||||||
|
if (e.target.checked) {
|
||||||
|
document.documentElement.setAttribute('data-theme', 'dark');
|
||||||
|
localStorage.setItem('theme', 'dark');
|
||||||
|
} else {
|
||||||
|
document.documentElement.setAttribute('data-theme', 'light');
|
||||||
|
localStorage.setItem('theme', 'light');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const toggleSwitch = document.querySelector('.theme-switch input[type="checkbox"]');
|
||||||
|
if (toggleSwitch !== null) {
|
||||||
|
toggleSwitch.addEventListener('change', switchTheme, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
var currentTheme = localStorage.getItem('theme');
|
||||||
|
if (!currentTheme && window.matchMedia('(prefers-color-scheme: dark)').matches) {
|
||||||
|
currentTheme = 'dark';
|
||||||
|
}
|
||||||
|
if (currentTheme) {
|
||||||
|
document.documentElement.setAttribute('data-theme', currentTheme);
|
||||||
|
|
||||||
|
if (currentTheme === 'dark' && toggleSwitch !== null) {
|
||||||
|
toggleSwitch.checked = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener('DOMContentLoaded', main);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="document" id="documentId">
|
||||||
|
<div class="container">
|
||||||
|
<h1 class="title">src/fiber_orm</h1>
|
||||||
|
<div class="row">
|
||||||
|
<div class="three columns">
|
||||||
|
<div class="theme-switch-wrapper">
|
||||||
|
<label class="theme-switch" for="checkbox">
|
||||||
|
<input type="checkbox" id="checkbox" />
|
||||||
|
<div class="slider round"></div>
|
||||||
|
</label>
|
||||||
|
<em>Dark Mode</em>
|
||||||
|
</div>
|
||||||
|
<div id="global-links">
|
||||||
|
<ul class="simple">
|
||||||
|
<li>
|
||||||
|
<a href="theindex.html">Index</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div id="searchInputDiv">
|
||||||
|
Search: <input type="text" id="searchInput"
|
||||||
|
onkeyup="search()" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
Group by:
|
||||||
|
<select onchange="groupBy(this.value)">
|
||||||
|
<option value="section">Section</option>
|
||||||
|
<option value="type">Type</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<ul class="simple simple-toc" id="toc-list">
|
||||||
|
<li><a class="reference" id="basic-usage_toc" href="#basic-usage">Basic Usage</a></li>
|
||||||
|
<ul class="simple"><li><a class="reference" id="basic-usage-example-db-schema_toc" href="#basic-usage-example-db-schema">Example DB Schema</a></li>
|
||||||
|
<li><a class="reference" id="basic-usage-example-model-definitions_toc" href="#basic-usage-example-model-definitions">Example Model Definitions</a></li>
|
||||||
|
<li><a class="reference" id="basic-usage-example-fiber-orm-usage_toc" href="#basic-usage-example-fiber-orm-usage">Example Fiber ORM Usage</a></li>
|
||||||
|
</ul><li><a class="reference" id="objectminusrelational-modeling_toc" href="#objectminusrelational-modeling">Object-Relational Modeling</a></li>
|
||||||
|
<ul class="simple"><li><a class="reference" id="objectminusrelational-modeling-model-class_toc" href="#objectminusrelational-modeling-model-class">Model Class</a></li>
|
||||||
|
<ul class="simple"><li><a class="reference" id="model-class-name-mapping_toc" href="#model-class-name-mapping">Name Mapping</a></li>
|
||||||
|
<li><a class="reference" id="model-class-id-field_toc" href="#model-class-id-field">ID Field</a></li>
|
||||||
|
</ul><li><a class="reference" id="objectminusrelational-modeling-supported-data-types_toc" href="#objectminusrelational-modeling-supported-data-types">Supported Data Types</a></li>
|
||||||
|
</ul><li><a class="reference" id="database-object_toc" href="#database-object">Database Object</a></li>
|
||||||
|
<li><a class="reference" id="see-also_toc" href="#see-also">See Also</a></li>
|
||||||
|
<li>
|
||||||
|
<a class="reference reference-toplevel" href="#6" id="56">Imports</a>
|
||||||
|
<ul class="simple simple-toc-section">
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a class="reference reference-toplevel" href="#7" id="57">Types</a>
|
||||||
|
<ul class="simple simple-toc-section">
|
||||||
|
<li><a class="reference" href="#NotFoundError"
|
||||||
|
title="NotFoundError = object of CatchableError">NotFoundError</a></li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a class="reference reference-toplevel" href="#12" id="62">Procs</a>
|
||||||
|
<ul class="simple simple-toc-section">
|
||||||
|
<ul class="simple nested-toc-section">createRecord
|
||||||
|
<li><a class="reference" href="#createRecord%2CDbConn%2CT"
|
||||||
|
title="createRecord[T](db: DbConn; rec: T): T">createRecord[T](db: DbConn; rec: T): T</a></li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
<ul class="simple nested-toc-section">deleteRecord
|
||||||
|
<li><a class="reference" href="#deleteRecord%2CDbConn%2CT"
|
||||||
|
title="deleteRecord[T](db: DbConn; rec: T): bool">deleteRecord[T](db: DbConn; rec: T): bool</a></li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
<ul class="simple nested-toc-section">initPool
|
||||||
|
<li><a class="reference" href="#initPool%2Cproc%29%2Cint%2Cstring"
|
||||||
|
title="initPool(connect: proc (): DbConn; poolSize = 10; hardCap = false;
|
||||||
|
healthCheckQuery = "SELECT \'true\' AS alive"): DbConnPool">initPool(connect: proc (): DbConn; poolSize = 10; hardCap = false;
|
||||||
|
healthCheckQuery = "SELECT \'true\' AS alive"): DbConnPool</a></li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
<ul class="simple nested-toc-section">updateRecord
|
||||||
|
<li><a class="reference" href="#updateRecord%2CDbConn%2CT"
|
||||||
|
title="updateRecord[T](db: DbConn; rec: T): bool">updateRecord[T](db: DbConn; rec: T): bool</a></li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a class="reference reference-toplevel" href="#17" id="67">Macros</a>
|
||||||
|
<ul class="simple simple-toc-section">
|
||||||
|
<ul class="simple nested-toc-section">generateLookup
|
||||||
|
<li><a class="reference" href="#generateLookup.m%2Ctype%2Ctype%2Cseq%5Bstring%5D"
|
||||||
|
title="generateLookup(dbType: type; modelType: type; fields: seq[string]): untyped">generateLookup(dbType: type; modelType: type; fields: seq[string]): untyped</a></li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
<ul class="simple nested-toc-section">generateProcsForFieldLookups
|
||||||
|
<li><a class="reference" href="#generateProcsForFieldLookups.m%2Ctype%2CopenArray%5Btuple%5Btype%2Cseq%5Bstring%5D%5D%5D"
|
||||||
|
title="generateProcsForFieldLookups(dbType: type; modelsAndFields: openArray[
|
||||||
|
tuple[t: type, fields: seq[string]]]): untyped">generateProcsForFieldLookups(dbType: type; modelsAndFields: openArray[
|
||||||
|
tuple[t: type, fields: seq[string]]]): untyped</a></li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
<ul class="simple nested-toc-section">generateProcsForModels
|
||||||
|
<li><a class="reference" href="#generateProcsForModels.m%2Ctype%2CopenArray%5Btype%5D"
|
||||||
|
title="generateProcsForModels(dbType: type; modelTypes: openArray[type]): untyped">generateProcsForModels(dbType: type; modelTypes: openArray[type]): untyped</a></li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a class="reference reference-toplevel" href="#18" id="68">Templates</a>
|
||||||
|
<ul class="simple simple-toc-section">
|
||||||
|
<ul class="simple nested-toc-section">deleteRecord
|
||||||
|
<li><a class="reference" href="#deleteRecord.t%2CDbConn%2Ctype%2Ctyped"
|
||||||
|
title="deleteRecord(db: DbConn; modelType: type; id: typed): untyped">deleteRecord(db: DbConn; modelType: type; id: typed): untyped</a></li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
<ul class="simple nested-toc-section">findRecordsBy
|
||||||
|
<li><a class="reference" href="#findRecordsBy.t%2CDbConn%2Ctype%2Cseq%5Btuple%5Bstring%2Cstring%5D%5D"
|
||||||
|
title="findRecordsBy(db: DbConn; modelType: type;
|
||||||
|
lookups: seq[tuple[field: string, value: string]]): untyped">findRecordsBy(db: DbConn; modelType: type;
|
||||||
|
lookups: seq[tuple[field: string, value: string]]): untyped</a></li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
<ul class="simple nested-toc-section">findRecordsWhere
|
||||||
|
<li><a class="reference" href="#findRecordsWhere.t%2CDbConn%2Ctype%2Cstring%2Cvarargs%5Bstring%2CdbFormat%5D"
|
||||||
|
title="findRecordsWhere(db: DbConn; modelType: type; whereClause: string;
|
||||||
|
values: varargs[string, dbFormat]): untyped">findRecordsWhere(db: DbConn; modelType: type; whereClause: string;
|
||||||
|
values: varargs[string, dbFormat]): untyped</a></li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
<ul class="simple nested-toc-section">getAllRecords
|
||||||
|
<li><a class="reference" href="#getAllRecords.t%2CDbConn%2Ctype"
|
||||||
|
title="getAllRecords(db: DbConn; modelType: type): untyped">getAllRecords(db: DbConn; modelType: type): untyped</a></li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
<ul class="simple nested-toc-section">getRecord
|
||||||
|
<li><a class="reference" href="#getRecord.t%2CDbConn%2Ctype%2Ctyped"
|
||||||
|
title="getRecord(db: DbConn; modelType: type; id: typed): untyped">getRecord(db: DbConn; modelType: type; id: typed): untyped</a></li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
<ul class="simple nested-toc-section">inTransaction
|
||||||
|
<li><a class="reference" href="#inTransaction.t%2CDbConnPool%2Cuntyped"
|
||||||
|
title="inTransaction(db: DbConnPool; body: untyped)">inTransaction(db: DbConnPool; body: untyped)</a></li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a class="reference reference-toplevel" href="#19" id="69">Exports</a>
|
||||||
|
<ul class="simple simple-toc-section">
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<a
|
||||||
|
href="https://github.com/jdbernard/fiber-orm/tree/version-1-6/src/fiber_orm.nim#L1"
|
||||||
|
class="link-seesrc" target="_blank">Source</a>
|
||||||
|
<a href="https://github.com/jdbernard/fiber-orm/edit/devel/src/fiber_orm.nim#L1" class="link-seesrc" target="_blank" >Edit</a>
|
||||||
|
|
||||||
|
<div class="nine columns" id="content">
|
||||||
|
<div id="tocRoot"></div>
|
||||||
|
|
||||||
|
<p class="module-desc"><p>Lightweight ORM supporting the <a class="reference external" href="https://nim-lang.org/docs/db_postgres.html">Postgres</a> and <a class="reference external" href="https://nim-lang.org/docs/db_sqlite.html">SQLite</a> databases in Nim. It supports a simple, opinionated model mapper to generate SQL queries based on Nim objects. It also includes a simple connection pooling implementation.</p>
|
||||||
|
<p>Fiber ORM is not intended to be a 100% all-cases-covered ORM that handles every potential data access pattern one might wish to implement. It is best thought of as a collection of common SQL generation patterns. It is intended to cover 90% of the common queries and functions one might write when implementing an SQL-based access layer. It is expected that there may be a few more complicated queries that need to be implemented to handle specific access patterns.</p>
|
||||||
|
<p>The simple mapping pattern provided by Fiber ORM also works well on top of databases that encapsulate data access logic in SQL with, for example, views.</p>
|
||||||
|
|
||||||
|
<h1><a class="toc-backref" id="basic-usage" href="#basic-usage">Basic Usage</a></h1><p>Consider a simple TODO list application that keeps track of TODO items as well as time logged against those items.</p>
|
||||||
|
|
||||||
|
<h2><a class="toc-backref" id="basic-usage-example-db-schema" href="#basic-usage-example-db-schema">Example DB Schema</a></h2><p>You might have a schema such as:</p>
|
||||||
|
<pre class="listing">create extension if not exists "pgcrypto";
|
||||||
|
|
||||||
|
create table todo_items columns (
|
||||||
|
id uuid not null primary key default gen_random_uuid(),
|
||||||
|
owner varchar not null,
|
||||||
|
summary varchar not null,
|
||||||
|
details varchar default null,
|
||||||
|
priority integer not null default 0,
|
||||||
|
related_todo_item_ids uuid[] not null default '{}'
|
||||||
|
);
|
||||||
|
|
||||||
|
create table time_entries columns (
|
||||||
|
id uuid not null primary key default gen_random_uuid(),
|
||||||
|
todo_item_id uuid not null references todo_items (id) on delete cascade,
|
||||||
|
start timestamp with timezone not null default current_timestamp,
|
||||||
|
stop timestamp with timezone default null,
|
||||||
|
);</pre>
|
||||||
|
<h2><a class="toc-backref" id="basic-usage-example-model-definitions" href="#basic-usage-example-model-definitions">Example Model Definitions</a></h2><p>Models may be defined as:</p>
|
||||||
|
<pre class="listing"><span class="Comment"># models.nim</span>
|
||||||
|
<span class="Keyword">import</span> <span class="Identifier">std</span><span class="Operator">/</span><span class="Identifier">options</span><span class="Punctuation">,</span> <span class="Identifier">std</span><span class="Operator">/</span><span class="Identifier">times</span>
|
||||||
|
<span class="Keyword">import</span> <span class="Identifier">uuids</span>
|
||||||
|
|
||||||
|
<span class="Keyword">type</span>
|
||||||
|
<span class="Identifier">TodoItem</span><span class="Operator">*</span> <span class="Operator">=</span> <span class="Keyword">object</span>
|
||||||
|
<span class="Identifier">id</span><span class="Operator">*:</span> <span class="Identifier">UUID</span>
|
||||||
|
<span class="Identifier">owner</span><span class="Operator">*:</span> <span class="Identifier">string</span>
|
||||||
|
<span class="Identifier">summary</span><span class="Operator">*:</span> <span class="Identifier">string</span>
|
||||||
|
<span class="Identifier">details</span><span class="Operator">*:</span> <span class="Identifier">Option</span><span class="Punctuation">[</span><span class="Identifier">string</span><span class="Punctuation">]</span>
|
||||||
|
<span class="Identifier">priority</span><span class="Operator">*:</span> <span class="Identifier">int</span>
|
||||||
|
<span class="Identifier">relatedTodoItemIds</span><span class="Operator">*:</span> <span class="Identifier">seq</span><span class="Punctuation">[</span><span class="Identifier">UUID</span><span class="Punctuation">]</span>
|
||||||
|
|
||||||
|
<span class="Identifier">TimeEntry</span><span class="Operator">*</span> <span class="Operator">=</span> <span class="Keyword">object</span>
|
||||||
|
<span class="Identifier">id</span><span class="Operator">*:</span> <span class="Identifier">UUID</span>
|
||||||
|
<span class="Identifier">todoItemId</span><span class="Operator">*:</span> <span class="Identifier">Option</span><span class="Punctuation">[</span><span class="Identifier">UUID</span><span class="Punctuation">]</span>
|
||||||
|
<span class="Identifier">start</span><span class="Operator">*:</span> <span class="Identifier">DateTime</span>
|
||||||
|
<span class="Identifier">stop</span><span class="Operator">*:</span> <span class="Identifier">Option</span><span class="Punctuation">[</span><span class="Identifier">DateTime</span><span class="Punctuation">]</span></pre>
|
||||||
|
<h2><a class="toc-backref" id="basic-usage-example-fiber-orm-usage" href="#basic-usage-example-fiber-orm-usage">Example Fiber ORM Usage</a></h2><p>Using Fiber ORM we can generate a data access layer with:</p>
|
||||||
|
<pre class="listing"><span class="Comment"># db.nim</span>
|
||||||
|
<span class="Keyword">import</span> <span class="Identifier">fiber_orm</span>
|
||||||
|
<span class="Keyword">import</span> <span class="Operator">./</span><span class="Identifier">models</span><span class="Operator">.</span><span class="Identifier">nim</span>
|
||||||
|
|
||||||
|
<span class="Keyword">type</span> <span class="Identifier">TodoDB</span><span class="Operator">*</span> <span class="Operator">=</span> <span class="Identifier">DbConnPool</span>
|
||||||
|
|
||||||
|
<span class="Keyword">proc</span> <span class="Identifier">initDb</span><span class="Operator">*</span><span class="Punctuation">(</span><span class="Identifier">connString</span><span class="Punctuation">:</span> <span class="Identifier">string</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">TodoDB</span> <span class="Operator">=</span>
|
||||||
|
<span class="Identifier">result</span> <span class="Operator">=</span> <span class="Identifier">fiber_orm</span><span class="Operator">.</span><span class="Identifier">initPool</span><span class="Punctuation">(</span>
|
||||||
|
<span class="Identifier">connect</span> <span class="Operator">=</span> <span class="Keyword">proc</span><span class="Punctuation">(</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">DbConn</span> <span class="Operator">=</span> <span class="Identifier">open</span><span class="Punctuation">(</span><span class="StringLit">""</span><span class="Punctuation">,</span> <span class="StringLit">""</span><span class="Punctuation">,</span> <span class="StringLit">""</span><span class="Punctuation">,</span> <span class="Identifier">connString</span><span class="Punctuation">)</span><span class="Punctuation">,</span>
|
||||||
|
<span class="Identifier">poolSize</span> <span class="Operator">=</span> <span class="DecNumber">20</span><span class="Punctuation">,</span>
|
||||||
|
<span class="Identifier">hardCap</span> <span class="Operator">=</span> <span class="Identifier">false</span><span class="Punctuation">)</span>
|
||||||
|
|
||||||
|
|
||||||
|
<span class="Identifier">generateProcsForModels</span><span class="Punctuation">(</span><span class="Identifier">TodoDB</span><span class="Punctuation">,</span> <span class="Punctuation">[</span><span class="Identifier">TodoItem</span><span class="Punctuation">,</span> <span class="Identifier">TimeEntry</span><span class="Punctuation">]</span><span class="Punctuation">)</span>
|
||||||
|
|
||||||
|
<span class="Identifier">generateLookup</span><span class="Punctuation">(</span><span class="Identifier">TodoDB</span><span class="Punctuation">,</span> <span class="Identifier">TimeEntry</span><span class="Punctuation">,</span> <span class="Operator">@</span><span class="Punctuation">[</span><span class="StringLit">"todoItemId"</span><span class="Punctuation">]</span><span class="Punctuation">)</span></pre><p>This will generate the following procedures:</p>
|
||||||
|
<pre class="listing"><span class="Keyword">proc</span> <span class="Identifier">getTodoItem</span><span class="Operator">*</span><span class="Punctuation">(</span><span class="Identifier">db</span><span class="Punctuation">:</span> <span class="Identifier">TodoDB</span><span class="Punctuation">,</span> <span class="Identifier">id</span><span class="Punctuation">:</span> <span class="Identifier">UUID</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">TodoItem</span><span class="Punctuation">;</span>
|
||||||
|
<span class="Keyword">proc</span> <span class="Identifier">getAllTodoItems</span><span class="Operator">*</span><span class="Punctuation">(</span><span class="Identifier">db</span><span class="Punctuation">:</span> <span class="Identifier">TodoDB</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">seq</span><span class="Punctuation">[</span><span class="Identifier">TodoItem</span><span class="Punctuation">]</span><span class="Punctuation">;</span>
|
||||||
|
<span class="Keyword">proc</span> <span class="Identifier">createTodoItem</span><span class="Operator">*</span><span class="Punctuation">(</span><span class="Identifier">db</span><span class="Punctuation">:</span> <span class="Identifier">TodoDB</span><span class="Punctuation">,</span> <span class="Identifier">rec</span><span class="Punctuation">:</span> <span class="Identifier">TodoItem</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">TodoItem</span><span class="Punctuation">;</span>
|
||||||
|
<span class="Keyword">proc</span> <span class="Identifier">updateTodoItem</span><span class="Operator">*</span><span class="Punctuation">(</span><span class="Identifier">db</span><span class="Punctuation">:</span> <span class="Identifier">TodoDB</span><span class="Punctuation">,</span> <span class="Identifier">rec</span><span class="Punctuation">:</span> <span class="Identifier">TodoItem</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">bool</span><span class="Punctuation">;</span>
|
||||||
|
<span class="Keyword">proc</span> <span class="Identifier">deleteTodoItem</span><span class="Operator">*</span><span class="Punctuation">(</span><span class="Identifier">db</span><span class="Punctuation">:</span> <span class="Identifier">TodoDB</span><span class="Punctuation">,</span> <span class="Identifier">rec</span><span class="Punctuation">:</span> <span class="Identifier">TodoItem</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">bool</span><span class="Punctuation">;</span>
|
||||||
|
<span class="Keyword">proc</span> <span class="Identifier">deleteTodoItem</span><span class="Operator">*</span><span class="Punctuation">(</span><span class="Identifier">db</span><span class="Punctuation">:</span> <span class="Identifier">TodoDB</span><span class="Punctuation">,</span> <span class="Identifier">id</span><span class="Punctuation">:</span> <span class="Identifier">UUID</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">bool</span><span class="Punctuation">;</span>
|
||||||
|
|
||||||
|
<span class="Keyword">proc</span> <span class="Identifier">findTodoItemsWhere</span><span class="Operator">*</span><span class="Punctuation">(</span><span class="Identifier">db</span><span class="Punctuation">:</span> <span class="Identifier">TodoDB</span><span class="Punctuation">,</span> <span class="Identifier">whereClause</span><span class="Punctuation">:</span> <span class="Identifier">string</span><span class="Punctuation">,</span>
|
||||||
|
<span class="Identifier">values</span><span class="Punctuation">:</span> <span class="Identifier">varargs</span><span class="Punctuation">[</span><span class="Identifier">string</span><span class="Punctuation">,</span> <span class="Identifier">dbFormat</span><span class="Punctuation">]</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">seq</span><span class="Punctuation">[</span><span class="Identifier">TodoItem</span><span class="Punctuation">]</span><span class="Punctuation">;</span>
|
||||||
|
|
||||||
|
<span class="Keyword">proc</span> <span class="Identifier">getTimeEntry</span><span class="Operator">*</span><span class="Punctuation">(</span><span class="Identifier">db</span><span class="Punctuation">:</span> <span class="Identifier">TodoDB</span><span class="Punctuation">,</span> <span class="Identifier">id</span><span class="Punctuation">:</span> <span class="Identifier">UUID</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">TimeEntry</span><span class="Punctuation">;</span>
|
||||||
|
<span class="Keyword">proc</span> <span class="Identifier">getAllTimeEntries</span><span class="Operator">*</span><span class="Punctuation">(</span><span class="Identifier">db</span><span class="Punctuation">:</span> <span class="Identifier">TodoDB</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">seq</span><span class="Punctuation">[</span><span class="Identifier">TimeEntry</span><span class="Punctuation">]</span><span class="Punctuation">;</span>
|
||||||
|
<span class="Keyword">proc</span> <span class="Identifier">createTimeEntry</span><span class="Operator">*</span><span class="Punctuation">(</span><span class="Identifier">db</span><span class="Punctuation">:</span> <span class="Identifier">TodoDB</span><span class="Punctuation">,</span> <span class="Identifier">rec</span><span class="Punctuation">:</span> <span class="Identifier">TimeEntry</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">TimeEntry</span><span class="Punctuation">;</span>
|
||||||
|
<span class="Keyword">proc</span> <span class="Identifier">updateTimeEntry</span><span class="Operator">*</span><span class="Punctuation">(</span><span class="Identifier">db</span><span class="Punctuation">:</span> <span class="Identifier">TodoDB</span><span class="Punctuation">,</span> <span class="Identifier">rec</span><span class="Punctuation">:</span> <span class="Identifier">TimeEntry</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">bool</span><span class="Punctuation">;</span>
|
||||||
|
<span class="Keyword">proc</span> <span class="Identifier">deleteTimeEntry</span><span class="Operator">*</span><span class="Punctuation">(</span><span class="Identifier">db</span><span class="Punctuation">:</span> <span class="Identifier">TodoDB</span><span class="Punctuation">,</span> <span class="Identifier">rec</span><span class="Punctuation">:</span> <span class="Identifier">TimeEntry</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">bool</span><span class="Punctuation">;</span>
|
||||||
|
<span class="Keyword">proc</span> <span class="Identifier">deleteTimeEntry</span><span class="Operator">*</span><span class="Punctuation">(</span><span class="Identifier">db</span><span class="Punctuation">:</span> <span class="Identifier">TodoDB</span><span class="Punctuation">,</span> <span class="Identifier">id</span><span class="Punctuation">:</span> <span class="Identifier">UUID</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">bool</span><span class="Punctuation">;</span>
|
||||||
|
|
||||||
|
<span class="Keyword">proc</span> <span class="Identifier">findTimeEntriesWhere</span><span class="Operator">*</span><span class="Punctuation">(</span><span class="Identifier">db</span><span class="Punctuation">:</span> <span class="Identifier">TodoDB</span><span class="Punctuation">,</span> <span class="Identifier">whereClause</span><span class="Punctuation">:</span> <span class="Identifier">string</span><span class="Punctuation">,</span>
|
||||||
|
<span class="Identifier">values</span><span class="Punctuation">:</span> <span class="Identifier">varargs</span><span class="Punctuation">[</span><span class="Identifier">string</span><span class="Punctuation">,</span> <span class="Identifier">dbFormat</span><span class="Punctuation">]</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">seq</span><span class="Punctuation">[</span><span class="Identifier">TimeEntry</span><span class="Punctuation">]</span><span class="Punctuation">;</span>
|
||||||
|
|
||||||
|
<span class="Keyword">proc</span> <span class="Identifier">findTimeEntriesByTodoItemId</span><span class="Punctuation">(</span><span class="Identifier">db</span><span class="Punctuation">:</span> <span class="Identifier">TodoDB</span><span class="Punctuation">,</span> <span class="Identifier">todoItemId</span><span class="Punctuation">:</span> <span class="Identifier">UUID</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">seq</span><span class="Punctuation">[</span><span class="Identifier">TimeEntry</span><span class="Punctuation">]</span><span class="Punctuation">;</span></pre>
|
||||||
|
<h1><a class="toc-backref" id="objectminusrelational-modeling" href="#objectminusrelational-modeling">Object-Relational Modeling</a></h1>
|
||||||
|
<h2><a class="toc-backref" id="objectminusrelational-modeling-model-class" href="#objectminusrelational-modeling-model-class">Model Class</a></h2><p>Fiber ORM uses simple Nim <tt class="docutils literal"><span class="pre"><span class="Keyword">object</span></span></tt>s and <tt class="docutils literal"><span class="pre"><span class="Keyword">ref</span> <span class="Keyword">object</span></span></tt>s as model classes. Fiber ORM expects there to be one table for each model class.</p>
|
||||||
|
|
||||||
|
<h3><a class="toc-backref" id="model-class-name-mapping" href="#model-class-name-mapping">Name Mapping</a></h3><p>Fiber ORM uses <tt class="docutils literal"><span class="pre"><span class="Identifier">snake_case</span></span></tt> for database identifiers (column names, table names, etc.) and <tt class="docutils literal"><span class="pre"><span class="Identifier">camelCase</span></span></tt> for Nim identifiers. We automatically convert model names to and from table names (<tt class="docutils literal"><span class="pre"><span class="Identifier">TodoItem</span></span></tt> <-> <tt class="docutils literal"><span class="pre"><span class="Identifier">todo_items</span></span></tt>), as well as column names (<tt class="docutils literal"><span class="pre"><span class="Identifier">userId</span></span></tt> <-> <tt class="docutils literal"><span class="pre"><span class="Identifier">user_id</span></span></tt>).</p>
|
||||||
|
<p>Notice that table names are automatically pluralized from model class names. In the above example, you have:</p>
|
||||||
|
<table border="1" class="docutils"><tr><th>Model Class</th><th>Table Name</th></tr>
|
||||||
|
<tr><td>TodoItem</td><td>todo_items</td></tr>
|
||||||
|
<tr><td>TimeEntry</td><td>time_entries</td></tr>
|
||||||
|
</table><p>Because Nim is style-insensitive, you can generall refer to model classes and fields using <tt class="docutils literal"><span class="pre"><span class="Identifier">snake_case</span></span></tt>, <tt class="docutils literal"><span class="pre"><span class="Identifier">camelCase</span></span></tt>, or <tt class="docutils literal"><span class="pre"><span class="Identifier">PascalCase</span></span></tt> in your code and expect Fiber ORM to be able to map the names to DB identifier names properly (though FiberORM will always use <tt class="docutils literal"><span class="pre"><span class="Identifier">camelCase</span></span></tt> internally).</p>
|
||||||
|
<p>See the <a class="reference external" href="fiber_orm/util.html#identNameToDb,string">identNameToDb</a>, <a class="reference external" href="fiber_orm/util.html#dbNameToIdent,string">dbNameToIdent</a>, <a class="reference external" href="fiber_orm/util.html#tableName,type">tableName</a> and <a class="reference external" href="fiber_orm/util.html#dbFormat,DateTime">dbFormat</a> procedures in the <a class="reference internal" href="#fiber">fiber</a> module for details.</p>
|
||||||
|
|
||||||
|
<h3><a class="toc-backref" id="model-class-id-field" href="#model-class-id-field">ID Field</a></h3><p>Fiber ORM expects every model class to have a field named <tt class="docutils literal"><span class="pre"><span class="Identifier">id</span></span></tt>, with a corresponding <tt class="docutils literal"><span class="pre"><span class="Identifier">id</span></span></tt> column in the model table. This field must be either a <tt class="docutils literal"><span class="pre"><span class="Identifier">string</span></span></tt>, <tt class="docutils literal"><span class="pre"><span class="Identifier">integer</span></span></tt>, or <a class="reference external" href="https://github.com/pragmagic/uuids">UUID</a>.</p>
|
||||||
|
<p>When creating a new record the <tt class="docutils literal"><span class="pre"><span class="Identifier">id</span></span></tt> field will be omitted if it is empty (<a class="reference external" href="https://nim-lang.org/docs/options.html#isNone,Option[T]">Option.isNone</a>, <a class="reference external" href="https://github.com/pragmagic/uuids/blob/8cb8720b567c6bcb261bd1c0f7491bdb5209ad06/uuids.nim#L72">UUID.isZero</a>, value of <tt class="docutils literal"><span class="pre"><span class="DecNumber">0</span></span></tt>, or only whitespace). This is intended to allow for cases like the example where the database may generate an ID when a new record is inserted. If a non-zero value is provided, the create call will include the <tt class="docutils literal"><span class="pre"><span class="Identifier">id</span></span></tt> field in the <tt class="docutils literal"><span class="pre"><span class="Identifier">INSERT</span></span></tt> query.</p>
|
||||||
|
<p>For example, to allow the database to create the id:</p>
|
||||||
|
<pre class="listing"><span class="Keyword">let</span> <span class="Identifier">item</span> <span class="Operator">=</span> <span class="Identifier">TodoItem</span><span class="Punctuation">(</span>
|
||||||
|
<span class="Identifier">owner</span><span class="Punctuation">:</span> <span class="StringLit">"John Mann"</span><span class="Punctuation">,</span>
|
||||||
|
<span class="Identifier">summary</span><span class="Punctuation">:</span> <span class="StringLit">"Create a grocery list."</span><span class="Punctuation">,</span>
|
||||||
|
<span class="Identifier">details</span><span class="Punctuation">:</span> <span class="Identifier">none</span><span class="Punctuation">[</span><span class="Identifier">string</span><span class="Punctuation">]</span><span class="Punctuation">(</span><span class="Punctuation">)</span><span class="Punctuation">,</span>
|
||||||
|
<span class="Identifier">priority</span><span class="Punctuation">:</span> <span class="DecNumber">0</span><span class="Punctuation">,</span>
|
||||||
|
<span class="Identifier">relatedTodoItemIds</span><span class="Punctuation">:</span> <span class="Operator">@</span><span class="Punctuation">[</span><span class="Punctuation">]</span><span class="Punctuation">)</span>
|
||||||
|
|
||||||
|
<span class="Keyword">let</span> <span class="Identifier">itemWithId</span> <span class="Operator">=</span> <span class="Identifier">db</span><span class="Operator">.</span><span class="Identifier">createTodoItem</span><span class="Punctuation">(</span><span class="Identifier">item</span><span class="Punctuation">)</span>
|
||||||
|
<span class="Identifier">echo</span> <span class="Operator">$</span><span class="Identifier">itemWithId</span><span class="Operator">.</span><span class="Identifier">id</span> <span class="Comment"># generated in the database</span></pre><p>And to create it in code:</p>
|
||||||
|
<pre class="listing"><span class="Keyword">import</span> <span class="Identifier">uuids</span>
|
||||||
|
|
||||||
|
<span class="Keyword">let</span> <span class="Identifier">item</span> <span class="Operator">=</span> <span class="Identifier">TodoItem</span><span class="Punctuation">(</span>
|
||||||
|
<span class="Identifier">id</span><span class="Punctuation">:</span> <span class="Identifier">genUUID</span><span class="Punctuation">(</span><span class="Punctuation">)</span><span class="Punctuation">,</span>
|
||||||
|
<span class="Identifier">owner</span><span class="Punctuation">:</span> <span class="StringLit">"John Mann"</span><span class="Punctuation">,</span>
|
||||||
|
<span class="Identifier">summary</span><span class="Punctuation">:</span> <span class="StringLit">"Create a grocery list."</span><span class="Punctuation">,</span>
|
||||||
|
<span class="Identifier">details</span><span class="Punctuation">:</span> <span class="Identifier">none</span><span class="Punctuation">[</span><span class="Identifier">string</span><span class="Punctuation">]</span><span class="Punctuation">(</span><span class="Punctuation">)</span><span class="Punctuation">,</span>
|
||||||
|
<span class="Identifier">priority</span><span class="Punctuation">:</span> <span class="DecNumber">0</span><span class="Punctuation">,</span>
|
||||||
|
<span class="Identifier">relatedTodoItemIds</span><span class="Punctuation">:</span> <span class="Operator">@</span><span class="Punctuation">[</span><span class="Punctuation">]</span><span class="Punctuation">)</span>
|
||||||
|
|
||||||
|
<span class="Keyword">let</span> <span class="Identifier">itemInDb</span> <span class="Operator">=</span> <span class="Identifier">db</span><span class="Operator">.</span><span class="Identifier">createTodoItem</span><span class="Punctuation">(</span><span class="Identifier">item</span><span class="Punctuation">)</span>
|
||||||
|
<span class="Identifier">echo</span> <span class="Operator">$</span><span class="Identifier">itemInDb</span><span class="Operator">.</span><span class="Identifier">id</span> <span class="Comment"># will be the same as what was provided</span></pre>
|
||||||
|
<h2><a class="toc-backref" id="objectminusrelational-modeling-supported-data-types" href="#objectminusrelational-modeling-supported-data-types">Supported Data Types</a></h2><p>The following Nim data types are supported by Fiber ORM:</p>
|
||||||
|
<table border="1" class="docutils"><tr><th>Nim Type</th><th>Postgres Type</th><th>SQLite Type</th></tr>
|
||||||
|
<tr><td><tt class="docutils literal"><span class="pre"><span class="Identifier">string</span></span></tt></td><td><a class="reference external" href="https://www.postgresql.org/docs/current/datatype-character.html">varchar</a></td><td></td></tr>
|
||||||
|
<tr><td><tt class="docutils literal"><span class="pre"><span class="Identifier">int</span></span></tt></td><td><a class="reference external" href="https://www.postgresql.org/docs/current/datatype-numeric.html#DATATYPE-INT">integer</a></td><td></td></tr>
|
||||||
|
<tr><td><tt class="docutils literal"><span class="pre"><span class="Identifier">float</span></span></tt></td><td><a class="reference external" href="https://www.postgresql.org/docs/current/datatype-numeric.html#DATATYPE-FLOAT">double</a></td><td></td></tr>
|
||||||
|
<tr><td><tt class="docutils literal"><span class="pre"><span class="Identifier">bool</span></span></tt></td><td><a class="reference external" href="https://www.postgresql.org/docs/current/datatype-boolean.html">boolean</a></td><td></td></tr>
|
||||||
|
<tr><td><a class="reference external" href="https://nim-lang.org/docs/times.html#DateTime">DateTime</a></td><td><a class="reference external" href="https://www.postgresql.org/docs/current/datatype-datetime.html">timestamp</a></td><td></td></tr>
|
||||||
|
<tr><td><tt class="docutils literal"><span class="pre"><span class="Identifier">seq</span><span class="Punctuation">[</span><span class="Punctuation">]</span></span></tt></td><td><a class="reference external" href="https://www.postgresql.org/docs/current/arrays.html">array</a></td><td></td></tr>
|
||||||
|
<tr><td><a class="reference external" href="https://github.com/pragmagic/uuids">UUID</a></td><td><a class="reference external" href="https://www.postgresql.org/docs/current/datatype-uuid.html">uuid (pg)</a></td><td></td></tr>
|
||||||
|
<tr><td><a class="reference external" href="https://nim-lang.org/docs/options.html#Option">Option</a></td><td><em>allows</em> <tt class="docutils literal"><span class="pre"><span class="Identifier">NULL</span></span></tt> <sup><strong><a class="reference internal" href="#footnote-f1">[1]</a></strong></sup></td><td></td></tr>
|
||||||
|
<tr><td><a class="reference external" href="https://nim-lang.org/docs/json.html#JsonNode">JsonNode</a></td><td><a class="reference external" href="https://www.postgresql.org/docs/current/datatype-json.html">jsonb</a></td><td></td></tr>
|
||||||
|
</table><hr class="footnote"><div class="footnote-group">
|
||||||
|
<div id="footnote-f1"><div class="footnote-label"><sup><strong><a href="#footnote-f1">[1]</a></strong></sup></div>   Note that this implies that all <tt class="docutils literal"><span class="pre"><span class="Identifier">NULL</span></span></tt>-able fields should be typed as optional using <tt class="docutils literal"><span class="pre"><span class="Identifier">Option</span><span class="Punctuation">[</span><span class="Identifier">fieldType</span><span class="Punctuation">]</span></span></tt>. Conversely, any fields with non-optional types should also be constrained to be <tt class="docutils literal"><span class="pre"><span class="Keyword">NOT</span> <span class="Identifier">NULL</span></span></tt> in the database schema.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h1><a class="toc-backref" id="database-object" href="#database-object">Database Object</a></h1><p>Many of the Fiber ORM macros expect a database object type to be passed. In the example above the <a class="reference external" href="fiber_orm/pool.html#DbConnPool">pool.DbConnPool</a> object is used as database object type (aliased as <tt class="docutils literal"><span class="pre"><span class="Identifier">TodoDB</span></span></tt>). This is the intended usage pattern, but anything can be passed as the database object type so long as there is a defined <tt class="docutils literal"><span class="pre"><span class="Identifier">withConn</span></span></tt> template that provides an injected <tt class="docutils literal"><span class="pre"><span class="Identifier">conn</span><span class="Punctuation">:</span> <span class="Identifier">DbConn</span></span></tt> object to the provided statement body.</p>
|
||||||
|
<p>For example, a valid database object implementation that opens a new connection for every request might look like this:</p>
|
||||||
|
<pre class="listing"><span class="Keyword">import</span> <span class="Identifier">std</span><span class="Operator">/</span><span class="Identifier">db_postgres</span>
|
||||||
|
|
||||||
|
<span class="Keyword">type</span> <span class="Identifier">TodoDB</span><span class="Operator">*</span> <span class="Operator">=</span> <span class="Keyword">object</span>
|
||||||
|
<span class="Identifier">connString</span><span class="Punctuation">:</span> <span class="Identifier">string</span>
|
||||||
|
|
||||||
|
<span class="Keyword">template</span> <span class="Identifier">withConn</span><span class="Operator">*</span><span class="Punctuation">(</span><span class="Identifier">db</span><span class="Punctuation">:</span> <span class="Identifier">TodoDB</span><span class="Punctuation">,</span> <span class="Identifier">stmt</span><span class="Punctuation">:</span> <span class="Identifier">untyped</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">untyped</span> <span class="Operator">=</span>
|
||||||
|
<span class="Keyword">let</span> <span class="Identifier">conn</span> <span class="Punctuation">{</span><span class="Operator">.</span><span class="Identifier">inject</span><span class="Operator">.</span><span class="Punctuation">}</span> <span class="Operator">=</span> <span class="Identifier">open</span><span class="Punctuation">(</span><span class="StringLit">""</span><span class="Punctuation">,</span> <span class="StringLit">""</span><span class="Punctuation">,</span> <span class="StringLit">""</span><span class="Punctuation">,</span> <span class="Identifier">db</span><span class="Operator">.</span><span class="Identifier">connString</span><span class="Punctuation">)</span>
|
||||||
|
<span class="Keyword">try</span><span class="Punctuation">:</span> <span class="Identifier">stmt</span>
|
||||||
|
<span class="Keyword">finally</span><span class="Punctuation">:</span> <span class="Identifier">close</span><span class="Punctuation">(</span><span class="Identifier">conn</span><span class="Punctuation">)</span></pre>
|
||||||
|
<h1><a class="toc-backref" id="see-also" href="#see-also">See Also</a></h1><p><a class="reference external" href="fiber_orm/pool.html">fiber_orm/pool</a></p>
|
||||||
|
</p>
|
||||||
|
<div class="section" id="6">
|
||||||
|
<h1><a class="toc-backref" href="#6">Imports</a></h1>
|
||||||
|
<dl class="item">
|
||||||
|
<a class="reference external" href="fiber_orm/pool.html">fiber_orm/pool</a>, <a class="reference external" href="fiber_orm/util.html">fiber_orm/util</a>
|
||||||
|
</dl></div>
|
||||||
|
<div class="section" id="7">
|
||||||
|
<h1><a class="toc-backref" href="#7">Types</a></h1>
|
||||||
|
<dl class="item">
|
||||||
|
<div id="NotFoundError">
|
||||||
|
<dt><pre><a href="fiber_orm.html#NotFoundError"><span class="Identifier">NotFoundError</span></a> <span class="Other">=</span> <span class="Keyword">object</span> <span class="Keyword">of</span> <span class="Identifier">CatchableError</span></pre></dt>
|
||||||
|
<dd>
|
||||||
|
|
||||||
|
|
||||||
|
Error type raised when no record matches a given ID
|
||||||
|
<a
|
||||||
|
href="https://github.com/jdbernard/fiber-orm/tree/version-1-6/src/fiber_orm.nim#L299"
|
||||||
|
class="link-seesrc" target="_blank">Source</a>
|
||||||
|
<a href="https://github.com/jdbernard/fiber-orm/edit/devel/src/fiber_orm.nim#L299" class="link-seesrc" target="_blank" >Edit</a>
|
||||||
|
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</dl></div>
|
||||||
|
<div class="section" id="12">
|
||||||
|
<h1><a class="toc-backref" href="#12">Procs</a></h1>
|
||||||
|
<dl class="item">
|
||||||
|
<div id="createRecord,DbConn,T">
|
||||||
|
<dt><pre><span class="Keyword">proc</span> <a href="#createRecord%2CDbConn%2CT"><span class="Identifier">createRecord</span></a><span class="Other">[</span><span class="Identifier">T</span><span class="Other">]</span><span class="Other">(</span><span class="Identifier">db</span><span class="Other">:</span> <span class="Identifier">DbConn</span><span class="Other">;</span> <span class="Identifier">rec</span><span class="Other">:</span> <span class="Identifier">T</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">T</span></pre></dt>
|
||||||
|
<dd>
|
||||||
|
|
||||||
|
<p>Create a new record. <tt class="docutils literal"><span class="pre"><span class="Identifier">rec</span></span></tt> is expected to be a <a class="reference external" href="#objectminusrelational-modeling-model-class">model class</a>. The <tt class="docutils literal"><span class="pre"><span class="Identifier">id</span></span></tt> field is only set if it is non-empty (see <a class="reference external" href="#model-class-id-field">ID Field</a> for details).</p>
|
||||||
|
<p>Returns the newly created record.</p>
|
||||||
|
|
||||||
|
<a
|
||||||
|
href="https://github.com/jdbernard/fiber-orm/tree/version-1-6/src/fiber_orm.nim#L314"
|
||||||
|
class="link-seesrc" target="_blank">Source</a>
|
||||||
|
<a href="https://github.com/jdbernard/fiber-orm/edit/devel/src/fiber_orm.nim#L314" class="link-seesrc" target="_blank" >Edit</a>
|
||||||
|
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
<div id="deleteRecord,DbConn,T">
|
||||||
|
<dt><pre><span class="Keyword">proc</span> <a href="#deleteRecord%2CDbConn%2CT"><span class="Identifier">deleteRecord</span></a><span class="Other">[</span><span class="Identifier">T</span><span class="Other">]</span><span class="Other">(</span><span class="Identifier">db</span><span class="Other">:</span> <span class="Identifier">DbConn</span><span class="Other">;</span> <span class="Identifier">rec</span><span class="Other">:</span> <span class="Identifier">T</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">bool</span></pre></dt>
|
||||||
|
<dd>
|
||||||
|
|
||||||
|
Delete a record by <a class="reference external" href="#model-class-id-field">id</a>.
|
||||||
|
<a
|
||||||
|
href="https://github.com/jdbernard/fiber-orm/tree/version-1-6/src/fiber_orm.nim#L359"
|
||||||
|
class="link-seesrc" target="_blank">Source</a>
|
||||||
|
<a href="https://github.com/jdbernard/fiber-orm/edit/devel/src/fiber_orm.nim#L359" class="link-seesrc" target="_blank" >Edit</a>
|
||||||
|
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
<div id="initPool,proc),int,string">
|
||||||
|
<dt><pre><span class="Keyword">proc</span> <a href="#initPool%2Cproc%29%2Cint%2Cstring"><span class="Identifier">initPool</span></a><span class="Other">(</span><span class="Identifier">connect</span><span class="Other">:</span> <span class="Keyword">proc</span> <span class="Other">(</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">DbConn</span><span class="Other">;</span> <span class="Identifier">poolSize</span> <span class="Other">=</span> <span class="DecNumber">10</span><span class="Other">;</span> <span class="Identifier">hardCap</span> <span class="Other">=</span> <span class="Identifier">false</span><span class="Other">;</span>
|
||||||
|
<span class="Identifier">healthCheckQuery</span> <span class="Other">=</span> <span class="StringLit">"SELECT \'true\' AS alive"</span><span class="Other">)</span><span class="Other">:</span> <a href="fiber_orm/pool.html#DbConnPool"><span class="Identifier">DbConnPool</span></a> {.
|
||||||
|
<span><span class="Other pragmadots">...</span></span><span class="pragmawrap"><span class="Identifier">raises</span><span class="Other">:</span> <span class="Other">[</span><span class="Identifier">Exception</span><span class="Other">]</span><span class="Other">,</span> <span class="Identifier">tags</span><span class="Other">:</span> <span class="Other">[</span><span class="Identifier">RootEffect</span><span class="Other">]</span></span>.}</pre></dt>
|
||||||
|
<dd>
|
||||||
|
|
||||||
|
Initialize a new DbConnPool. See the <tt class="docutils literal"><span class="pre"><span class="Identifier">initDb</span></span></tt> procedure in the <a class="reference external" href="#basic-usage-example-fiber-orm-usage">Example Fiber ORM Usage</a> for an example<ul class="simple"><li><tt class="docutils literal"><span class="pre"><span class="Identifier">connect</span></span></tt> must be a factory which creates a new <tt class="docutils literal"><span class="pre"><span class="Identifier">DbConn</span></span></tt>.</li>
|
||||||
|
<li><tt class="docutils literal"><span class="pre"><span class="Identifier">poolSize</span></span></tt> sets the desired capacity of the connection pool.</li>
|
||||||
|
<li><p><tt class="docutils literal"><span class="pre"><span class="Identifier">hardCap</span></span></tt> defaults to <tt class="docutils literal"><span class="pre"><span class="Identifier">false</span></span></tt>. When <tt class="docutils literal"><span class="pre"><span class="Identifier">false</span></span></tt>, the pool can grow beyond the configured capacity, but will release connections down to the its capacity (no less than <tt class="docutils literal"><span class="pre"><span class="Identifier">poolSize</span></span></tt>).</p>
|
||||||
|
<p>When <tt class="docutils literal"><span class="pre"><span class="Identifier">true</span></span></tt> the pool will not create more than its configured capacity. It a connection is requested, none are free, and the pool is at capacity, this will result in an Error being raised.</p>
|
||||||
|
</li>
|
||||||
|
<li><tt class="docutils literal"><span class="pre"><span class="Identifier">healthCheckQuery</span></span></tt> should be a simple and fast SQL query that the pool can use to test the liveliness of pooled connections.</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<a
|
||||||
|
href="https://github.com/jdbernard/fiber-orm/tree/version-1-6/src/fiber_orm.nim#L539"
|
||||||
|
class="link-seesrc" target="_blank">Source</a>
|
||||||
|
<a href="https://github.com/jdbernard/fiber-orm/edit/devel/src/fiber_orm.nim#L539" class="link-seesrc" target="_blank" >Edit</a>
|
||||||
|
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
<div id="updateRecord,DbConn,T">
|
||||||
|
<dt><pre><span class="Keyword">proc</span> <a href="#updateRecord%2CDbConn%2CT"><span class="Identifier">updateRecord</span></a><span class="Other">[</span><span class="Identifier">T</span><span class="Other">]</span><span class="Other">(</span><span class="Identifier">db</span><span class="Other">:</span> <span class="Identifier">DbConn</span><span class="Other">;</span> <span class="Identifier">rec</span><span class="Other">:</span> <span class="Identifier">T</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">bool</span></pre></dt>
|
||||||
|
<dd>
|
||||||
|
|
||||||
|
Update a record by id. <tt class="docutils literal"><span class="pre"><span class="Identifier">rec</span></span></tt> is expected to be a <a class="reference external" href="#objectminusrelational-modeling-model-class">model class</a>.
|
||||||
|
<a
|
||||||
|
href="https://github.com/jdbernard/fiber-orm/tree/version-1-6/src/fiber_orm.nim#L337"
|
||||||
|
class="link-seesrc" target="_blank">Source</a>
|
||||||
|
<a href="https://github.com/jdbernard/fiber-orm/edit/devel/src/fiber_orm.nim#L337" class="link-seesrc" target="_blank" >Edit</a>
|
||||||
|
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</dl></div>
|
||||||
|
<div class="section" id="17">
|
||||||
|
<h1><a class="toc-backref" href="#17">Macros</a></h1>
|
||||||
|
<dl class="item">
|
||||||
|
<div id="generateLookup.m,type,type,seq[string]">
|
||||||
|
<dt><pre><span class="Keyword">macro</span> <a href="#generateLookup.m%2Ctype%2Ctype%2Cseq%5Bstring%5D"><span class="Identifier">generateLookup</span></a><span class="Other">(</span><span class="Identifier">dbType</span><span class="Other">:</span> <span class="Identifier">type</span><span class="Other">;</span> <span class="Identifier">modelType</span><span class="Other">:</span> <span class="Identifier">type</span><span class="Other">;</span> <span class="Identifier">fields</span><span class="Other">:</span> <span class="Identifier">seq</span><span class="Other">[</span><span class="Identifier">string</span><span class="Other">]</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">untyped</span></pre></dt>
|
||||||
|
<dd>
|
||||||
|
|
||||||
|
Create a lookup procedure for a given set of field names. For example, given the TODO database demostrated above,<pre class="listing"><span class="Identifier">generateLookup</span><span class="Punctuation">(</span><span class="Identifier">TodoDB</span><span class="Punctuation">,</span> <span class="Identifier">TodoItem</span><span class="Punctuation">,</span> <span class="Punctuation">[</span><span class="StringLit">"owner"</span><span class="Punctuation">,</span> <span class="StringLit">"priority"</span><span class="Punctuation">]</span><span class="Punctuation">)</span></pre><p>will generate the following procedure:</p>
|
||||||
|
<pre class="listing"><span class="Keyword">proc</span> <span class="Identifier">findTodoItemsByOwnerAndPriority</span><span class="Operator">*</span><span class="Punctuation">(</span><span class="Identifier">db</span><span class="Punctuation">:</span> <span class="Identifier">SampleDB</span><span class="Punctuation">,</span>
|
||||||
|
<span class="Identifier">owner</span><span class="Punctuation">:</span> <span class="Identifier">string</span><span class="Punctuation">,</span> <span class="Identifier">priority</span><span class="Punctuation">:</span> <span class="Identifier">int</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">seq</span><span class="Punctuation">[</span><span class="Identifier">TodoItem</span><span class="Punctuation">]</span></pre>
|
||||||
|
<a
|
||||||
|
href="https://github.com/jdbernard/fiber-orm/tree/version-1-6/src/fiber_orm.nim#L468"
|
||||||
|
class="link-seesrc" target="_blank">Source</a>
|
||||||
|
<a href="https://github.com/jdbernard/fiber-orm/edit/devel/src/fiber_orm.nim#L468" class="link-seesrc" target="_blank" >Edit</a>
|
||||||
|
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
<div id="generateProcsForFieldLookups.m,type,openArray[tuple[type,seq[string]]]">
|
||||||
|
<dt><pre><span class="Keyword">macro</span> <a href="#generateProcsForFieldLookups.m%2Ctype%2CopenArray%5Btuple%5Btype%2Cseq%5Bstring%5D%5D%5D"><span class="Identifier">generateProcsForFieldLookups</span></a><span class="Other">(</span><span class="Identifier">dbType</span><span class="Other">:</span> <span class="Identifier">type</span><span class="Other">;</span> <span class="Identifier">modelsAndFields</span><span class="Other">:</span> <span class="Identifier">openArray</span><span class="Other">[</span>
|
||||||
|
<span class="Keyword">tuple</span><span class="Other">[</span><span class="Identifier">t</span><span class="Other">:</span> <span class="Identifier">type</span><span class="Other">,</span> <span class="Identifier">fields</span><span class="Other">:</span> <span class="Identifier">seq</span><span class="Other">[</span><span class="Identifier">string</span><span class="Other">]</span><span class="Other">]</span><span class="Other">]</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">untyped</span></pre></dt>
|
||||||
|
<dd>
|
||||||
|
|
||||||
|
|
||||||
|
<a
|
||||||
|
href="https://github.com/jdbernard/fiber-orm/tree/version-1-6/src/fiber_orm.nim#L510"
|
||||||
|
class="link-seesrc" target="_blank">Source</a>
|
||||||
|
<a href="https://github.com/jdbernard/fiber-orm/edit/devel/src/fiber_orm.nim#L510" class="link-seesrc" target="_blank" >Edit</a>
|
||||||
|
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
<div id="generateProcsForModels.m,type,openArray[type]">
|
||||||
|
<dt><pre><span class="Keyword">macro</span> <a href="#generateProcsForModels.m%2Ctype%2CopenArray%5Btype%5D"><span class="Identifier">generateProcsForModels</span></a><span class="Other">(</span><span class="Identifier">dbType</span><span class="Other">:</span> <span class="Identifier">type</span><span class="Other">;</span> <span class="Identifier">modelTypes</span><span class="Other">:</span> <span class="Identifier">openArray</span><span class="Other">[</span><span class="Identifier">type</span><span class="Other">]</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">untyped</span></pre></dt>
|
||||||
|
<dd>
|
||||||
|
|
||||||
|
Generate all standard access procedures for the given model types. For a <a class="reference external" href="#objectminusrelational-modeling-model-class">model class</a> named <tt class="docutils literal"><span class="pre"><span class="Identifier">TodoItem</span></span></tt>, this will generate the following procedures:<pre class="listing"><span class="Keyword">proc</span> <span class="Identifier">getTodoItem</span><span class="Operator">*</span><span class="Punctuation">(</span><span class="Identifier">db</span><span class="Punctuation">:</span> <span class="Identifier">TodoDB</span><span class="Punctuation">,</span> <span class="Identifier">id</span><span class="Punctuation">:</span> <span class="Identifier">idType</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">TodoItem</span><span class="Punctuation">;</span>
|
||||||
|
<span class="Keyword">proc</span> <span class="Identifier">getAllTodoItems</span><span class="Operator">*</span><span class="Punctuation">(</span><span class="Identifier">db</span><span class="Punctuation">:</span> <span class="Identifier">TodoDB</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">TodoItem</span><span class="Punctuation">;</span>
|
||||||
|
<span class="Keyword">proc</span> <span class="Identifier">createTodoItem</span><span class="Operator">*</span><span class="Punctuation">(</span><span class="Identifier">db</span><span class="Punctuation">:</span> <span class="Identifier">TodoDB</span><span class="Punctuation">,</span> <span class="Identifier">rec</span><span class="Punctuation">:</span> <span class="Identifier">TodoItem</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">TodoItem</span><span class="Punctuation">;</span>
|
||||||
|
<span class="Keyword">proc</span> <span class="Identifier">deleteTodoItem</span><span class="Operator">*</span><span class="Punctuation">(</span><span class="Identifier">db</span><span class="Punctuation">:</span> <span class="Identifier">TodoDB</span><span class="Punctuation">,</span> <span class="Identifier">rec</span><span class="Punctuation">:</span> <span class="Identifier">TodoItem</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">bool</span><span class="Punctuation">;</span>
|
||||||
|
<span class="Keyword">proc</span> <span class="Identifier">deleteTodoItem</span><span class="Operator">*</span><span class="Punctuation">(</span><span class="Identifier">db</span><span class="Punctuation">:</span> <span class="Identifier">TodoDB</span><span class="Punctuation">,</span> <span class="Identifier">id</span><span class="Punctuation">:</span> <span class="Identifier">idType</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">bool</span><span class="Punctuation">;</span>
|
||||||
|
<span class="Keyword">proc</span> <span class="Identifier">updateTodoItem</span><span class="Operator">*</span><span class="Punctuation">(</span><span class="Identifier">db</span><span class="Punctuation">:</span> <span class="Identifier">TodoDB</span><span class="Punctuation">,</span> <span class="Identifier">rec</span><span class="Punctuation">:</span> <span class="Identifier">TodoItem</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">bool</span><span class="Punctuation">;</span>
|
||||||
|
|
||||||
|
<span class="Keyword">proc</span> <span class="Identifier">findTodoItemsWhere</span><span class="Operator">*</span><span class="Punctuation">(</span>
|
||||||
|
<span class="Identifier">db</span><span class="Punctuation">:</span> <span class="Identifier">TodoDB</span><span class="Punctuation">,</span> <span class="Identifier">whereClause</span><span class="Punctuation">:</span> <span class="Identifier">string</span><span class="Punctuation">,</span> <span class="Identifier">values</span><span class="Punctuation">:</span> <span class="Identifier">varargs</span><span class="Punctuation">[</span><span class="Identifier">string</span><span class="Punctuation">]</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">TodoItem</span><span class="Punctuation">;</span></pre><p><tt class="docutils literal"><span class="pre"><span class="Identifier">dbType</span></span></tt> is expected to be some type that has a defined <tt class="docutils literal"><span class="pre"><span class="Identifier">withConn</span></span></tt> procedure (see <a class="reference external" href="#database-object">Database Object</a> for details).</p>
|
||||||
|
|
||||||
|
<a
|
||||||
|
href="https://github.com/jdbernard/fiber-orm/tree/version-1-6/src/fiber_orm.nim#L414"
|
||||||
|
class="link-seesrc" target="_blank">Source</a>
|
||||||
|
<a href="https://github.com/jdbernard/fiber-orm/edit/devel/src/fiber_orm.nim#L414" class="link-seesrc" target="_blank" >Edit</a>
|
||||||
|
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</dl></div>
|
||||||
|
<div class="section" id="18">
|
||||||
|
<h1><a class="toc-backref" href="#18">Templates</a></h1>
|
||||||
|
<dl class="item">
|
||||||
|
<div id="deleteRecord.t,DbConn,type,typed">
|
||||||
|
<dt><pre><span class="Keyword">template</span> <a href="#deleteRecord.t%2CDbConn%2Ctype%2Ctyped"><span class="Identifier">deleteRecord</span></a><span class="Other">(</span><span class="Identifier">db</span><span class="Other">:</span> <span class="Identifier">DbConn</span><span class="Other">;</span> <span class="Identifier">modelType</span><span class="Other">:</span> <span class="Identifier">type</span><span class="Other">;</span> <span class="Identifier">id</span><span class="Other">:</span> <span class="Identifier">typed</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">untyped</span></pre></dt>
|
||||||
|
<dd>
|
||||||
|
|
||||||
|
Delete a record by id.
|
||||||
|
<a
|
||||||
|
href="https://github.com/jdbernard/fiber-orm/tree/version-1-6/src/fiber_orm.nim#L353"
|
||||||
|
class="link-seesrc" target="_blank">Source</a>
|
||||||
|
<a href="https://github.com/jdbernard/fiber-orm/edit/devel/src/fiber_orm.nim#L353" class="link-seesrc" target="_blank" >Edit</a>
|
||||||
|
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
<div id="findRecordsBy.t,DbConn,type,seq[tuple[string,string]]">
|
||||||
|
<dt><pre><span class="Keyword">template</span> <a href="#findRecordsBy.t%2CDbConn%2Ctype%2Cseq%5Btuple%5Bstring%2Cstring%5D%5D"><span class="Identifier">findRecordsBy</span></a><span class="Other">(</span><span class="Identifier">db</span><span class="Other">:</span> <span class="Identifier">DbConn</span><span class="Other">;</span> <span class="Identifier">modelType</span><span class="Other">:</span> <span class="Identifier">type</span><span class="Other">;</span>
|
||||||
|
<span class="Identifier">lookups</span><span class="Other">:</span> <span class="Identifier">seq</span><span class="Other">[</span><span class="Keyword">tuple</span><span class="Other">[</span><span class="Identifier">field</span><span class="Other">:</span> <span class="Identifier">string</span><span class="Other">,</span> <span class="Identifier">value</span><span class="Other">:</span> <span class="Identifier">string</span><span class="Other">]</span><span class="Other">]</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">untyped</span></pre></dt>
|
||||||
|
<dd>
|
||||||
|
|
||||||
|
Find all records matching the provided lookup values.
|
||||||
|
<a
|
||||||
|
href="https://github.com/jdbernard/fiber-orm/tree/version-1-6/src/fiber_orm.nim#L403"
|
||||||
|
class="link-seesrc" target="_blank">Source</a>
|
||||||
|
<a href="https://github.com/jdbernard/fiber-orm/edit/devel/src/fiber_orm.nim#L403" class="link-seesrc" target="_blank" >Edit</a>
|
||||||
|
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
<div id="findRecordsWhere.t,DbConn,type,string,varargs[string,dbFormat]">
|
||||||
|
<dt><pre><span class="Keyword">template</span> <a href="#findRecordsWhere.t%2CDbConn%2Ctype%2Cstring%2Cvarargs%5Bstring%2CdbFormat%5D"><span class="Identifier">findRecordsWhere</span></a><span class="Other">(</span><span class="Identifier">db</span><span class="Other">:</span> <span class="Identifier">DbConn</span><span class="Other">;</span> <span class="Identifier">modelType</span><span class="Other">:</span> <span class="Identifier">type</span><span class="Other">;</span> <span class="Identifier">whereClause</span><span class="Other">:</span> <span class="Identifier">string</span><span class="Other">;</span>
|
||||||
|
<span class="Identifier">values</span><span class="Other">:</span> <span class="Identifier">varargs</span><span class="Other">[</span><span class="Identifier">string</span><span class="Other">,</span> <span class="Identifier">dbFormat</span><span class="Other">]</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">untyped</span></pre></dt>
|
||||||
|
<dd>
|
||||||
|
|
||||||
|
Find all records matching a given <tt class="docutils literal"><span class="pre"><span class="Identifier">WHERE</span></span></tt> clause. The number of elements in the <tt class="docutils literal"><span class="pre"><span class="Identifier">values</span></span></tt> array must match the number of placeholders (<tt class="docutils literal"><span class="pre"><span class="Operator">?</span></span></tt>) in the provided <tt class="docutils literal"><span class="pre"><span class="Identifier">WHERE</span></span></tt> clause.
|
||||||
|
<a
|
||||||
|
href="https://github.com/jdbernard/fiber-orm/tree/version-1-6/src/fiber_orm.nim#L382"
|
||||||
|
class="link-seesrc" target="_blank">Source</a>
|
||||||
|
<a href="https://github.com/jdbernard/fiber-orm/edit/devel/src/fiber_orm.nim#L382" class="link-seesrc" target="_blank" >Edit</a>
|
||||||
|
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
<div id="getAllRecords.t,DbConn,type">
|
||||||
|
<dt><pre><span class="Keyword">template</span> <a href="#getAllRecords.t%2CDbConn%2Ctype"><span class="Identifier">getAllRecords</span></a><span class="Other">(</span><span class="Identifier">db</span><span class="Other">:</span> <span class="Identifier">DbConn</span><span class="Other">;</span> <span class="Identifier">modelType</span><span class="Other">:</span> <span class="Identifier">type</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">untyped</span></pre></dt>
|
||||||
|
<dd>
|
||||||
|
|
||||||
|
Fetch all records of the given type.
|
||||||
|
<a
|
||||||
|
href="https://github.com/jdbernard/fiber-orm/tree/version-1-6/src/fiber_orm.nim#L394"
|
||||||
|
class="link-seesrc" target="_blank">Source</a>
|
||||||
|
<a href="https://github.com/jdbernard/fiber-orm/edit/devel/src/fiber_orm.nim#L394" class="link-seesrc" target="_blank" >Edit</a>
|
||||||
|
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
<div id="getRecord.t,DbConn,type,typed">
|
||||||
|
<dt><pre><span class="Keyword">template</span> <a href="#getRecord.t%2CDbConn%2Ctype%2Ctyped"><span class="Identifier">getRecord</span></a><span class="Other">(</span><span class="Identifier">db</span><span class="Other">:</span> <span class="Identifier">DbConn</span><span class="Other">;</span> <span class="Identifier">modelType</span><span class="Other">:</span> <span class="Identifier">type</span><span class="Other">;</span> <span class="Identifier">id</span><span class="Other">:</span> <span class="Identifier">typed</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">untyped</span></pre></dt>
|
||||||
|
<dd>
|
||||||
|
|
||||||
|
Fetch a record by id.
|
||||||
|
<a
|
||||||
|
href="https://github.com/jdbernard/fiber-orm/tree/version-1-6/src/fiber_orm.nim#L367"
|
||||||
|
class="link-seesrc" target="_blank">Source</a>
|
||||||
|
<a href="https://github.com/jdbernard/fiber-orm/edit/devel/src/fiber_orm.nim#L367" class="link-seesrc" target="_blank" >Edit</a>
|
||||||
|
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
<div id="inTransaction.t,DbConnPool,untyped">
|
||||||
|
<dt><pre><span class="Keyword">template</span> <a href="#inTransaction.t%2CDbConnPool%2Cuntyped"><span class="Identifier">inTransaction</span></a><span class="Other">(</span><span class="Identifier">db</span><span class="Other">:</span> <a href="fiber_orm/pool.html#DbConnPool"><span class="Identifier">DbConnPool</span></a><span class="Other">;</span> <span class="Identifier">body</span><span class="Other">:</span> <span class="Identifier">untyped</span><span class="Other">)</span></pre></dt>
|
||||||
|
<dd>
|
||||||
|
|
||||||
|
|
||||||
|
<a
|
||||||
|
href="https://github.com/jdbernard/fiber-orm/tree/version-1-6/src/fiber_orm.nim#L567"
|
||||||
|
class="link-seesrc" target="_blank">Source</a>
|
||||||
|
<a href="https://github.com/jdbernard/fiber-orm/edit/devel/src/fiber_orm.nim#L567" class="link-seesrc" target="_blank" >Edit</a>
|
||||||
|
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</dl></div>
|
||||||
|
<div class="section" id="19">
|
||||||
|
<h1><a class="toc-backref" href="#19">Exports</a></h1>
|
||||||
|
<dl class="item">
|
||||||
|
<a href="fiber_orm/pool.html#DbConnPoolConfig"><span class="Identifier">DbConnPoolConfig</span></a>, <a href="fiber_orm/pool.html#initDbConnPool,DbConnPoolConfig"><span class="Identifier">initDbConnPool</span></a>, <a href="fiber_orm/pool.html#withConn.t,DbConnPool,untyped"><span class="Identifier">withConn</span></a>, <a href="fiber_orm/pool.html#take,DbConnPool"><span class="Identifier">take</span></a>, <a href="fiber_orm/pool.html#DbConnPool"><span class="Identifier">DbConnPool</span></a>, <a href="fiber_orm/pool.html#release,DbConnPool,int"><span class="Identifier">release</span></a>, <a href="fiber_orm/util.html#columnNamesForModel.m,typed"><span class="Identifier">columnNamesForModel</span></a>, <a href="fiber_orm/util.html#dbFormat,DateTime"><span class="Identifier">dbFormat</span></a>, <a href="fiber_orm/util.html#dbFormat,seq[T]"><span class="Identifier">dbFormat</span></a>, <a href="fiber_orm/util.html#dbFormat,string"><span class="Identifier">dbFormat</span></a>, <a href="fiber_orm/util.html#dbFormat,T"><span class="Identifier">dbFormat</span></a>, <a href="fiber_orm/util.html#dbNameToIdent,string"><span class="Identifier">dbNameToIdent</span></a>, <a href="fiber_orm/util.html#identNameToDb,string"><span class="Identifier">identNameToDb</span></a>, <a href="fiber_orm/util.html#modelName.m,type"><span class="Identifier">modelName</span></a>, <a href="fiber_orm/util.html#modelName.m"><span class="Identifier">modelName</span></a>, <a href="fiber_orm/util.html#rowToModel.m,typed,seq[string]"><span class="Identifier">rowToModel</span></a>, <a href="fiber_orm/util.html#tableName,type"><span class="Identifier">tableName</span></a>, <a href="fiber_orm/util.html#tableName,T"><span class="Identifier">tableName</span></a>
|
||||||
|
</dl></div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="twelve-columns footer">
|
||||||
|
<span class="nim-sprite"></span>
|
||||||
|
<br/>
|
||||||
|
<small style="color: var(--hint);">Made with Nim. Generated: 2022-09-04 02:31:20 UTC</small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
25
docs/fiber_orm.idx
Normal file
25
docs/fiber_orm.idx
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
NotFoundError fiber_orm.html#NotFoundError fiber_orm: NotFoundError
|
||||||
|
createRecord fiber_orm.html#createRecord,DbConn,T fiber_orm: createRecord[T](db: DbConn; rec: T): T
|
||||||
|
updateRecord fiber_orm.html#updateRecord,DbConn,T fiber_orm: updateRecord[T](db: DbConn; rec: T): bool
|
||||||
|
deleteRecord fiber_orm.html#deleteRecord.t,DbConn,type,typed fiber_orm: deleteRecord(db: DbConn; modelType: type; id: typed): untyped
|
||||||
|
deleteRecord fiber_orm.html#deleteRecord,DbConn,T fiber_orm: deleteRecord[T](db: DbConn; rec: T): bool
|
||||||
|
getRecord fiber_orm.html#getRecord.t,DbConn,type,typed fiber_orm: getRecord(db: DbConn; modelType: type; id: typed): untyped
|
||||||
|
findRecordsWhere fiber_orm.html#findRecordsWhere.t,DbConn,type,string,varargs[string,dbFormat] fiber_orm: findRecordsWhere(db: DbConn; modelType: type; whereClause: string;\n values: varargs[string, dbFormat]): untyped
|
||||||
|
getAllRecords fiber_orm.html#getAllRecords.t,DbConn,type fiber_orm: getAllRecords(db: DbConn; modelType: type): untyped
|
||||||
|
findRecordsBy fiber_orm.html#findRecordsBy.t,DbConn,type,seq[tuple[string,string]] fiber_orm: findRecordsBy(db: DbConn; modelType: type;\n lookups: seq[tuple[field: string, value: string]]): untyped
|
||||||
|
generateProcsForModels fiber_orm.html#generateProcsForModels.m,type,openArray[type] fiber_orm: generateProcsForModels(dbType: type; modelTypes: openArray[type]): untyped
|
||||||
|
generateLookup fiber_orm.html#generateLookup.m,type,type,seq[string] fiber_orm: generateLookup(dbType: type; modelType: type; fields: seq[string]): untyped
|
||||||
|
generateProcsForFieldLookups fiber_orm.html#generateProcsForFieldLookups.m,type,openArray[tuple[type,seq[string]]] fiber_orm: generateProcsForFieldLookups(dbType: type; modelsAndFields: openArray[\n tuple[t: type, fields: seq[string]]]): untyped
|
||||||
|
initPool fiber_orm.html#initPool,proc),int,string fiber_orm: initPool(connect: proc (): DbConn; poolSize = 10; hardCap = false;\n healthCheckQuery = "SELECT \'true\' AS alive"): DbConnPool
|
||||||
|
inTransaction fiber_orm.html#inTransaction.t,DbConnPool,untyped fiber_orm: inTransaction(db: DbConnPool; body: untyped)
|
||||||
|
Basic Usage fiber_orm.html#basic-usage Basic Usage
|
||||||
|
Example DB Schema fiber_orm.html#basic-usage-example-db-schema Example DB Schema
|
||||||
|
Example Model Definitions fiber_orm.html#basic-usage-example-model-definitions Example Model Definitions
|
||||||
|
Example Fiber ORM Usage fiber_orm.html#basic-usage-example-fiber-orm-usage Example Fiber ORM Usage
|
||||||
|
Object-Relational Modeling fiber_orm.html#objectminusrelational-modeling Object-Relational Modeling
|
||||||
|
Model Class fiber_orm.html#objectminusrelational-modeling-model-class Model Class
|
||||||
|
Name Mapping fiber_orm.html#model-class-name-mapping Name Mapping
|
||||||
|
ID Field fiber_orm.html#model-class-id-field ID Field
|
||||||
|
Supported Data Types fiber_orm.html#objectminusrelational-modeling-supported-data-types Supported Data Types
|
||||||
|
Database Object fiber_orm.html#database-object Database Object
|
||||||
|
See Also fiber_orm.html#see-also See Also
|
303
docs/fiber_orm/pool.html
Normal file
303
docs/fiber_orm/pool.html
Normal file
@ -0,0 +1,303 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
||||||
|
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||||
|
<!-- This file is generated by Nim. -->
|
||||||
|
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||||
|
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
|
||||||
|
<!-- Favicon -->
|
||||||
|
<link rel="shortcut icon" href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAUAAAAF////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAIAAABbAAAAlQAAAKIAAACbAAAAmwAAAKIAAACVAAAAWwAAAAL///8A////AP///wD///8A////AAAAABQAAADAAAAAYwAAAA3///8A////AP///wD///8AAAAADQAAAGMAAADAAAAAFP///wD///8A////AP///wAAAACdAAAAOv///wD///8A////AP///wD///8A////AP///wD///8AAAAAOgAAAJ3///8A////AP///wAAAAAnAAAAcP///wAAAAAoAAAASv///wD///8A////AP///wAAAABKAAAAKP///wAAAABwAAAAJ////wD///8AAAAAgQAAABwAAACIAAAAkAAAAJMAAACtAAAAFQAAABUAAACtAAAAkwAAAJAAAACIAAAAHAAAAIH///8A////AAAAAKQAAACrAAAAaP///wD///8AAAAARQAAANIAAADSAAAARf///wD///8AAAAAaAAAAKsAAACk////AAAAADMAAACcAAAAnQAAABj///8A////AP///wAAAAAYAAAAGP///wD///8A////AAAAABgAAACdAAAAnAAAADMAAAB1AAAAwwAAAP8AAADpAAAAsQAAAE4AAAAb////AP///wAAAAAbAAAATgAAALEAAADpAAAA/wAAAMMAAAB1AAAAtwAAAOkAAAD/AAAA/wAAAP8AAADvAAAA3gAAAN4AAADeAAAA3gAAAO8AAAD/AAAA/wAAAP8AAADpAAAAtwAAAGUAAAA/AAAA3wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAADfAAAAPwAAAGX///8A////AAAAAEgAAADtAAAAvwAAAL0AAADGAAAA7wAAAO8AAADGAAAAvQAAAL8AAADtAAAASP///wD///8A////AP///wD///8AAAAAO////wD///8A////AAAAAIcAAACH////AP///wD///8AAAAAO////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A//8AAP//AAD4HwAA7/cAAN/7AAD//wAAoYUAAJ55AACf+QAAh+EAAAAAAADAAwAA4AcAAP5/AAD//wAA//8AAA=="/>
|
||||||
|
<link rel="icon" type="image/png" sizes="32x32" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAA3XAAAN1wFCKJt4AAAAB3RJTUUH4QQQEwksSS9ZWwAAAk1JREFUWMPtll2ITVEUx39nn/O7Y5qR8f05wtCUUr6ZIS++8pEnkZInPImneaCQ5METNdOkeFBKUhMPRIkHKfEuUZSUlGlKPN2TrgfncpvmnntnmlEyq1Z7t89/rf9a6+y99oZxGZf/XeIq61EdtgKXgdXA0xrYAvBjOIF1AI9zvjcC74BSpndrJPkBWDScTF8Aa4E3wDlgHbASaANmVqlcCnwHvgDvgVfAJ+AikAAvgfVZwLnSVZHZaOuKoQi3ZOMi4NkYkpe1p4J7A8BpYAD49hfIy/oqG0+hLomiKP2L5L+1ubn5115S+3OAn4EnwBlgMzCjyt6ZAnQCJ4A7wOs88iRJHvw50HoujuPBoCKwHWiosy8MdfZnAdcHk8dxXFJ3VQbQlCTJvRBCGdRbD4M6uc5glpY3eAihpN5S5w12diSEcCCEcKUO4ljdr15T76ur1FDDLIQQ3qv71EdDOe3Kxj3leRXyk+pxdWnFWod6Wt2bY3de3aSuUHcPBVimHs7mK9WrmeOF6lR1o9qnzskh2ar2qm1qizpfXaPeVGdlmGN5pb09qMxz1Xb1kLqgzn1RyH7JUXW52lr5e/Kqi9qpto7V1atuUzfnARrV7jEib1T76gG2qxdGmXyiekkt1GswPTtek0aBfJp6YySGBfWg2tPQ0FAYgf1stUfdmdcjarbYJEniKIq6gY/Aw+zWHAC+p2labGpqiorFYgGYCEzN7oQdQClN07O1/EfDyGgC0ALMBdYAi4FyK+4H3gLPsxfR1zRNi+NP7nH5J+QntnXe5B5mpfQAAAAASUVORK5CYII=">
|
||||||
|
|
||||||
|
<!-- Google fonts -->
|
||||||
|
<link href='https://fonts.googleapis.com/css?family=Lato:400,600,900' rel='stylesheet' type='text/css'/>
|
||||||
|
<link href='https://fonts.googleapis.com/css?family=Source+Code+Pro:400,500,600' rel='stylesheet' type='text/css'/>
|
||||||
|
|
||||||
|
<!-- CSS -->
|
||||||
|
<title>src/fiber_orm/pool</title>
|
||||||
|
<link rel="stylesheet" type="text/css" href="../nimdoc.out.css">
|
||||||
|
|
||||||
|
<script type="text/javascript" src="../dochack.js"></script>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
function main() {
|
||||||
|
var pragmaDots = document.getElementsByClassName("pragmadots");
|
||||||
|
for (var i = 0; i < pragmaDots.length; i++) {
|
||||||
|
pragmaDots[i].onclick = function(event) {
|
||||||
|
// Hide tease
|
||||||
|
event.target.parentNode.style.display = "none";
|
||||||
|
// Show actual
|
||||||
|
event.target.parentNode.nextElementSibling.style.display = "inline";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function switchTheme(e) {
|
||||||
|
if (e.target.checked) {
|
||||||
|
document.documentElement.setAttribute('data-theme', 'dark');
|
||||||
|
localStorage.setItem('theme', 'dark');
|
||||||
|
} else {
|
||||||
|
document.documentElement.setAttribute('data-theme', 'light');
|
||||||
|
localStorage.setItem('theme', 'light');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const toggleSwitch = document.querySelector('.theme-switch input[type="checkbox"]');
|
||||||
|
if (toggleSwitch !== null) {
|
||||||
|
toggleSwitch.addEventListener('change', switchTheme, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
var currentTheme = localStorage.getItem('theme');
|
||||||
|
if (!currentTheme && window.matchMedia('(prefers-color-scheme: dark)').matches) {
|
||||||
|
currentTheme = 'dark';
|
||||||
|
}
|
||||||
|
if (currentTheme) {
|
||||||
|
document.documentElement.setAttribute('data-theme', currentTheme);
|
||||||
|
|
||||||
|
if (currentTheme === 'dark' && toggleSwitch !== null) {
|
||||||
|
toggleSwitch.checked = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener('DOMContentLoaded', main);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="document" id="documentId">
|
||||||
|
<div class="container">
|
||||||
|
<h1 class="title">src/fiber_orm/pool</h1>
|
||||||
|
<div class="row">
|
||||||
|
<div class="three columns">
|
||||||
|
<div class="theme-switch-wrapper">
|
||||||
|
<label class="theme-switch" for="checkbox">
|
||||||
|
<input type="checkbox" id="checkbox" />
|
||||||
|
<div class="slider round"></div>
|
||||||
|
</label>
|
||||||
|
<em>Dark Mode</em>
|
||||||
|
</div>
|
||||||
|
<div id="global-links">
|
||||||
|
<ul class="simple">
|
||||||
|
<li>
|
||||||
|
<a href="../theindex.html">Index</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div id="searchInputDiv">
|
||||||
|
Search: <input type="text" id="searchInput"
|
||||||
|
onkeyup="search()" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
Group by:
|
||||||
|
<select onchange="groupBy(this.value)">
|
||||||
|
<option value="section">Section</option>
|
||||||
|
<option value="type">Type</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<ul class="simple simple-toc" id="toc-list">
|
||||||
|
<li>
|
||||||
|
<a class="reference reference-toplevel" href="#7" id="57">Types</a>
|
||||||
|
<ul class="simple simple-toc-section">
|
||||||
|
<li><a class="reference" href="#DbConnPool"
|
||||||
|
title="DbConnPool = ref object
|
||||||
|
conns: seq[PooledDbConn]
|
||||||
|
cfg: DbConnPoolConfig
|
||||||
|
lastId: int">DbConnPool</a></li>
|
||||||
|
<li><a class="reference" href="#DbConnPoolConfig"
|
||||||
|
title="DbConnPoolConfig = object
|
||||||
|
connect*: () -> DbConn ## Factory procedure to create a new DBConn
|
||||||
|
poolSize*: int ## The pool capacity.
|
||||||
|
hardCap*: bool ## Is the pool capacity a hard cap?
|
||||||
|
##
|
||||||
|
## When `false`, the pool can grow beyond the configured
|
||||||
|
## capacity, but will release connections down to the its
|
||||||
|
## capacity (no less than `poolSize`).
|
||||||
|
##
|
||||||
|
## When `true` the pool will not create more than its
|
||||||
|
## configured capacity. It a connection is requested, none
|
||||||
|
## are free, and the pool is at capacity, this will result
|
||||||
|
## in an Error being raised.
|
||||||
|
healthCheckQuery*: string ## Should be a simple and fast SQL query that the
|
||||||
|
## pool can use to test the liveliness of pooled
|
||||||
|
## connections.">DbConnPoolConfig</a></li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a class="reference reference-toplevel" href="#12" id="62">Procs</a>
|
||||||
|
<ul class="simple simple-toc-section">
|
||||||
|
<ul class="simple nested-toc-section">initDbConnPool
|
||||||
|
<li><a class="reference" href="#initDbConnPool%2CDbConnPoolConfig"
|
||||||
|
title="initDbConnPool(cfg: DbConnPoolConfig): DbConnPool">initDbConnPool(cfg: DbConnPoolConfig): DbConnPool</a></li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
<ul class="simple nested-toc-section">release
|
||||||
|
<li><a class="reference" href="#release%2CDbConnPool%2Cint"
|
||||||
|
title="release(pool: DbConnPool; connId: int): void">release(pool: DbConnPool; connId: int): void</a></li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
<ul class="simple nested-toc-section">take
|
||||||
|
<li><a class="reference" href="#take%2CDbConnPool"
|
||||||
|
title="take(pool: DbConnPool): tuple[id: int, conn: DbConn]">take(pool: DbConnPool): tuple[id: int, conn: DbConn]</a></li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a class="reference reference-toplevel" href="#18" id="68">Templates</a>
|
||||||
|
<ul class="simple simple-toc-section">
|
||||||
|
<ul class="simple nested-toc-section">withConn
|
||||||
|
<li><a class="reference" href="#withConn.t%2CDbConnPool%2Cuntyped"
|
||||||
|
title="withConn(pool: DbConnPool; stmt: untyped): untyped">withConn(pool: DbConnPool; stmt: untyped): untyped</a></li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<a
|
||||||
|
href="https://github.com/jdbernard/fiber-orm/tree/version-1-6/src/fiber_orm/pool.nim#L1"
|
||||||
|
class="link-seesrc" target="_blank">Source</a>
|
||||||
|
<a href="https://github.com/jdbernard/fiber-orm/edit/devel/src/fiber_orm/pool.nim#L1" class="link-seesrc" target="_blank" >Edit</a>
|
||||||
|
|
||||||
|
<div class="nine columns" id="content">
|
||||||
|
<div id="tocRoot"></div>
|
||||||
|
|
||||||
|
<p class="module-desc">Simple database connection pooling implementation compatible with Fiber ORM.</p>
|
||||||
|
<div class="section" id="7">
|
||||||
|
<h1><a class="toc-backref" href="#7">Types</a></h1>
|
||||||
|
<dl class="item">
|
||||||
|
<div id="DbConnPool">
|
||||||
|
<dt><pre><a href="pool.html#DbConnPool"><span class="Identifier">DbConnPool</span></a> <span class="Other">=</span> <span class="Keyword">ref</span> <span class="Keyword">object</span>
|
||||||
|
<span class="Identifier">conns</span><span class="Other">:</span> <span class="Identifier">seq</span><span class="Other">[</span><span class="Identifier">PooledDbConn</span><span class="Other">]</span>
|
||||||
|
<span class="Identifier">cfg</span><span class="Other">:</span> <a href="pool.html#DbConnPoolConfig"><span class="Identifier">DbConnPoolConfig</span></a>
|
||||||
|
<span class="Identifier">lastId</span><span class="Other">:</span> <span class="Identifier">int</span>
|
||||||
|
</pre></dt>
|
||||||
|
<dd>
|
||||||
|
|
||||||
|
Database connection pool
|
||||||
|
<a
|
||||||
|
href="https://github.com/jdbernard/fiber-orm/tree/version-1-6/src/fiber_orm/pool.nim#L35"
|
||||||
|
class="link-seesrc" target="_blank">Source</a>
|
||||||
|
<a href="https://github.com/jdbernard/fiber-orm/edit/devel/src/fiber_orm/pool.nim#L35" class="link-seesrc" target="_blank" >Edit</a>
|
||||||
|
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
<div id="DbConnPoolConfig">
|
||||||
|
<dt><pre><a href="pool.html#DbConnPoolConfig"><span class="Identifier">DbConnPoolConfig</span></a> <span class="Other">=</span> <span class="Keyword">object</span>
|
||||||
|
<span class="Identifier">connect</span><span class="Operator">*</span><span class="Other">:</span> <span class="Other">(</span><span class="Other">)</span> <span class="Operator">-></span> <span class="Identifier">DbConn</span> <span class="Comment">## Factory procedure to create a new DBConn</span>
|
||||||
|
<span class="Identifier">poolSize</span><span class="Operator">*</span><span class="Other">:</span> <span class="Identifier">int</span> <span class="Comment">## The pool capacity.</span>
|
||||||
|
<span class="Identifier">hardCap</span><span class="Operator">*</span><span class="Other">:</span> <span class="Identifier">bool</span> <span class="Comment">## Is the pool capacity a hard cap?</span>
|
||||||
|
<span class="Comment">## </span>
|
||||||
|
<span class="Comment">## When `false`, the pool can grow beyond the configured</span>
|
||||||
|
<span class="Comment">## capacity, but will release connections down to the its</span>
|
||||||
|
<span class="Comment">## capacity (no less than `poolSize`).</span>
|
||||||
|
<span class="Comment">## </span>
|
||||||
|
<span class="Comment">## When `true` the pool will not create more than its</span>
|
||||||
|
<span class="Comment">## configured capacity. It a connection is requested, none</span>
|
||||||
|
<span class="Comment">## are free, and the pool is at capacity, this will result</span>
|
||||||
|
<span class="Comment">## in an Error being raised.</span>
|
||||||
|
<span class="Identifier">healthCheckQuery</span><span class="Operator">*</span><span class="Other">:</span> <span class="Identifier">string</span> <span class="Comment">## Should be a simple and fast SQL query that the</span>
|
||||||
|
<span class="Comment">## pool can use to test the liveliness of pooled</span>
|
||||||
|
<span class="Comment">## connections.</span>
|
||||||
|
</pre></dt>
|
||||||
|
<dd>
|
||||||
|
|
||||||
|
|
||||||
|
<a
|
||||||
|
href="https://github.com/jdbernard/fiber-orm/tree/version-1-6/src/fiber_orm/pool.nim#L13"
|
||||||
|
class="link-seesrc" target="_blank">Source</a>
|
||||||
|
<a href="https://github.com/jdbernard/fiber-orm/edit/devel/src/fiber_orm/pool.nim#L13" class="link-seesrc" target="_blank" >Edit</a>
|
||||||
|
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</dl></div>
|
||||||
|
<div class="section" id="12">
|
||||||
|
<h1><a class="toc-backref" href="#12">Procs</a></h1>
|
||||||
|
<dl class="item">
|
||||||
|
<div id="initDbConnPool,DbConnPoolConfig">
|
||||||
|
<dt><pre><span class="Keyword">proc</span> <a href="#initDbConnPool%2CDbConnPoolConfig"><span class="Identifier">initDbConnPool</span></a><span class="Other">(</span><span class="Identifier">cfg</span><span class="Other">:</span> <a href="pool.html#DbConnPoolConfig"><span class="Identifier">DbConnPoolConfig</span></a><span class="Other">)</span><span class="Other">:</span> <a href="pool.html#DbConnPool"><span class="Identifier">DbConnPool</span></a> {.<span><span class="Other pragmadots">...</span></span><span class="pragmawrap"><span class="Identifier">raises</span><span class="Other">:</span> <span class="Other">[</span><span class="Identifier">Exception</span><span class="Other">]</span><span class="Other">,</span>
|
||||||
|
<span class="Identifier">tags</span><span class="Other">:</span> <span class="Other">[</span><span class="Identifier">RootEffect</span><span class="Other">]</span></span>.}</pre></dt>
|
||||||
|
<dd>
|
||||||
|
|
||||||
|
|
||||||
|
<a
|
||||||
|
href="https://github.com/jdbernard/fiber-orm/tree/version-1-6/src/fiber_orm/pool.nim#L47"
|
||||||
|
class="link-seesrc" target="_blank">Source</a>
|
||||||
|
<a href="https://github.com/jdbernard/fiber-orm/edit/devel/src/fiber_orm/pool.nim#L47" class="link-seesrc" target="_blank" >Edit</a>
|
||||||
|
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
<div id="release,DbConnPool,int">
|
||||||
|
<dt><pre><span class="Keyword">proc</span> <a href="#release%2CDbConnPool%2Cint"><span class="Identifier">release</span></a><span class="Other">(</span><span class="Identifier">pool</span><span class="Other">:</span> <a href="pool.html#DbConnPool"><span class="Identifier">DbConnPool</span></a><span class="Other">;</span> <span class="Identifier">connId</span><span class="Other">:</span> <span class="Identifier">int</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">void</span> {.
|
||||||
|
<span><span class="Other pragmadots">...</span></span><span class="pragmawrap"><span class="Identifier">raises</span><span class="Other">:</span> <span class="Other">[</span><span class="Identifier">Exception</span><span class="Other">,</span> <span class="Identifier">ValueError</span><span class="Other">]</span><span class="Other">,</span> <span class="Identifier">tags</span><span class="Other">:</span> <span class="Other">[</span><span class="Identifier">RootEffect</span><span class="Other">]</span></span>.}</pre></dt>
|
||||||
|
<dd>
|
||||||
|
|
||||||
|
Release a connection back to the pool.
|
||||||
|
<a
|
||||||
|
href="https://github.com/jdbernard/fiber-orm/tree/version-1-6/src/fiber_orm/pool.nim#L116"
|
||||||
|
class="link-seesrc" target="_blank">Source</a>
|
||||||
|
<a href="https://github.com/jdbernard/fiber-orm/edit/devel/src/fiber_orm/pool.nim#L116" class="link-seesrc" target="_blank" >Edit</a>
|
||||||
|
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
<div id="take,DbConnPool">
|
||||||
|
<dt><pre><span class="Keyword">proc</span> <a href="#take%2CDbConnPool"><span class="Identifier">take</span></a><span class="Other">(</span><span class="Identifier">pool</span><span class="Other">:</span> <a href="pool.html#DbConnPool"><span class="Identifier">DbConnPool</span></a><span class="Other">)</span><span class="Other">:</span> <span class="Keyword">tuple</span><span class="Other">[</span><span class="Identifier">id</span><span class="Other">:</span> <span class="Identifier">int</span><span class="Other">,</span> <span class="Identifier">conn</span><span class="Other">:</span> <span class="Identifier">DbConn</span><span class="Other">]</span> {.
|
||||||
|
<span><span class="Other pragmadots">...</span></span><span class="pragmawrap"><span class="Identifier">raises</span><span class="Other">:</span> <span class="Other">[</span><span class="Identifier">Exception</span><span class="Other">,</span> <span class="Identifier">ValueError</span><span class="Other">]</span><span class="Other">,</span> <span class="Identifier">tags</span><span class="Other">:</span> <span class="Other">[</span><span class="Identifier">RootEffect</span><span class="Other">,</span> <span class="Identifier">ReadDbEffect</span><span class="Other">,</span> <span class="Identifier">DbEffect</span><span class="Other">]</span></span>.}</pre></dt>
|
||||||
|
<dd>
|
||||||
|
|
||||||
|
<p>Request a connection from the pool. Returns a DbConn if the pool has free connections, or if it has the capacity to create a new connection. If the pool is configured with a hard capacity limit and is out of free connections, this will raise an Error.</p>
|
||||||
|
<p>Connections taken must be returned via <tt class="docutils literal"><span class="pre"><span class="Identifier">release</span></span></tt> when the caller is finished using them in order for them to be released back to the pool.</p>
|
||||||
|
|
||||||
|
<a
|
||||||
|
href="https://github.com/jdbernard/fiber-orm/tree/version-1-6/src/fiber_orm/pool.nim#L94"
|
||||||
|
class="link-seesrc" target="_blank">Source</a>
|
||||||
|
<a href="https://github.com/jdbernard/fiber-orm/edit/devel/src/fiber_orm/pool.nim#L94" class="link-seesrc" target="_blank" >Edit</a>
|
||||||
|
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</dl></div>
|
||||||
|
<div class="section" id="18">
|
||||||
|
<h1><a class="toc-backref" href="#18">Templates</a></h1>
|
||||||
|
<dl class="item">
|
||||||
|
<div id="withConn.t,DbConnPool,untyped">
|
||||||
|
<dt><pre><span class="Keyword">template</span> <a href="#withConn.t%2CDbConnPool%2Cuntyped"><span class="Identifier">withConn</span></a><span class="Other">(</span><span class="Identifier">pool</span><span class="Other">:</span> <a href="pool.html#DbConnPool"><span class="Identifier">DbConnPool</span></a><span class="Other">;</span> <span class="Identifier">stmt</span><span class="Other">:</span> <span class="Identifier">untyped</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">untyped</span></pre></dt>
|
||||||
|
<dd>
|
||||||
|
|
||||||
|
<p>Convenience template to provide a connection from the pool for use in a statement block, automatically releasing that connnection when done.</p>
|
||||||
|
<p>The provided connection is injected as the variable <tt class="docutils literal"><span class="pre"><span class="Identifier">conn</span></span></tt> in the statement body.</p>
|
||||||
|
|
||||||
|
<a
|
||||||
|
href="https://github.com/jdbernard/fiber-orm/tree/version-1-6/src/fiber_orm/pool.nim#L122"
|
||||||
|
class="link-seesrc" target="_blank">Source</a>
|
||||||
|
<a href="https://github.com/jdbernard/fiber-orm/edit/devel/src/fiber_orm/pool.nim#L122" class="link-seesrc" target="_blank" >Edit</a>
|
||||||
|
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</dl></div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="twelve-columns footer">
|
||||||
|
<span class="nim-sprite"></span>
|
||||||
|
<br/>
|
||||||
|
<small style="color: var(--hint);">Made with Nim. Generated: 2022-09-04 02:31:19 UTC</small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
6
docs/fiber_orm/pool.idx
Normal file
6
docs/fiber_orm/pool.idx
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
DbConnPoolConfig fiber_orm/pool.html#DbConnPoolConfig pool: DbConnPoolConfig
|
||||||
|
DbConnPool fiber_orm/pool.html#DbConnPool pool: DbConnPool
|
||||||
|
initDbConnPool fiber_orm/pool.html#initDbConnPool,DbConnPoolConfig pool: initDbConnPool(cfg: DbConnPoolConfig): DbConnPool
|
||||||
|
take fiber_orm/pool.html#take,DbConnPool pool: take(pool: DbConnPool): tuple[id: int, conn: DbConn]
|
||||||
|
release fiber_orm/pool.html#release,DbConnPool,int pool: release(pool: DbConnPool; connId: int): void
|
||||||
|
withConn fiber_orm/pool.html#withConn.t,DbConnPool,untyped pool: withConn(pool: DbConnPool; stmt: untyped): untyped
|
524
docs/fiber_orm/util.html
Normal file
524
docs/fiber_orm/util.html
Normal file
@ -0,0 +1,524 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
||||||
|
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||||
|
<!-- This file is generated by Nim. -->
|
||||||
|
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||||
|
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
|
||||||
|
<!-- Favicon -->
|
||||||
|
<link rel="shortcut icon" href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAUAAAAF////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAIAAABbAAAAlQAAAKIAAACbAAAAmwAAAKIAAACVAAAAWwAAAAL///8A////AP///wD///8A////AAAAABQAAADAAAAAYwAAAA3///8A////AP///wD///8AAAAADQAAAGMAAADAAAAAFP///wD///8A////AP///wAAAACdAAAAOv///wD///8A////AP///wD///8A////AP///wD///8AAAAAOgAAAJ3///8A////AP///wAAAAAnAAAAcP///wAAAAAoAAAASv///wD///8A////AP///wAAAABKAAAAKP///wAAAABwAAAAJ////wD///8AAAAAgQAAABwAAACIAAAAkAAAAJMAAACtAAAAFQAAABUAAACtAAAAkwAAAJAAAACIAAAAHAAAAIH///8A////AAAAAKQAAACrAAAAaP///wD///8AAAAARQAAANIAAADSAAAARf///wD///8AAAAAaAAAAKsAAACk////AAAAADMAAACcAAAAnQAAABj///8A////AP///wAAAAAYAAAAGP///wD///8A////AAAAABgAAACdAAAAnAAAADMAAAB1AAAAwwAAAP8AAADpAAAAsQAAAE4AAAAb////AP///wAAAAAbAAAATgAAALEAAADpAAAA/wAAAMMAAAB1AAAAtwAAAOkAAAD/AAAA/wAAAP8AAADvAAAA3gAAAN4AAADeAAAA3gAAAO8AAAD/AAAA/wAAAP8AAADpAAAAtwAAAGUAAAA/AAAA3wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAADfAAAAPwAAAGX///8A////AAAAAEgAAADtAAAAvwAAAL0AAADGAAAA7wAAAO8AAADGAAAAvQAAAL8AAADtAAAASP///wD///8A////AP///wD///8AAAAAO////wD///8A////AAAAAIcAAACH////AP///wD///8AAAAAO////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A//8AAP//AAD4HwAA7/cAAN/7AAD//wAAoYUAAJ55AACf+QAAh+EAAAAAAADAAwAA4AcAAP5/AAD//wAA//8AAA=="/>
|
||||||
|
<link rel="icon" type="image/png" sizes="32x32" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAA3XAAAN1wFCKJt4AAAAB3RJTUUH4QQQEwksSS9ZWwAAAk1JREFUWMPtll2ITVEUx39nn/O7Y5qR8f05wtCUUr6ZIS++8pEnkZInPImneaCQ5METNdOkeFBKUhMPRIkHKfEuUZSUlGlKPN2TrgfncpvmnntnmlEyq1Z7t89/rf9a6+y99oZxGZf/XeIq61EdtgKXgdXA0xrYAvBjOIF1AI9zvjcC74BSpndrJPkBWDScTF8Aa4E3wDlgHbASaANmVqlcCnwHvgDvgVfAJ+AikAAvgfVZwLnSVZHZaOuKoQi3ZOMi4NkYkpe1p4J7A8BpYAD49hfIy/oqG0+hLomiKP2L5L+1ubn5115S+3OAn4EnwBlgMzCjyt6ZAnQCJ4A7wOs88iRJHvw50HoujuPBoCKwHWiosy8MdfZnAdcHk8dxXFJ3VQbQlCTJvRBCGdRbD4M6uc5glpY3eAihpN5S5w12diSEcCCEcKUO4ljdr15T76ur1FDDLIQQ3qv71EdDOe3Kxj3leRXyk+pxdWnFWod6Wt2bY3de3aSuUHcPBVimHs7mK9WrmeOF6lR1o9qnzskh2ar2qm1qizpfXaPeVGdlmGN5pb09qMxz1Xb1kLqgzn1RyH7JUXW52lr5e/Kqi9qpto7V1atuUzfnARrV7jEib1T76gG2qxdGmXyiekkt1GswPTtek0aBfJp6YySGBfWg2tPQ0FAYgf1stUfdmdcjarbYJEniKIq6gY/Aw+zWHAC+p2labGpqiorFYgGYCEzN7oQdQClN07O1/EfDyGgC0ALMBdYAi4FyK+4H3gLPsxfR1zRNi+NP7nH5J+QntnXe5B5mpfQAAAAASUVORK5CYII=">
|
||||||
|
|
||||||
|
<!-- Google fonts -->
|
||||||
|
<link href='https://fonts.googleapis.com/css?family=Lato:400,600,900' rel='stylesheet' type='text/css'/>
|
||||||
|
<link href='https://fonts.googleapis.com/css?family=Source+Code+Pro:400,500,600' rel='stylesheet' type='text/css'/>
|
||||||
|
|
||||||
|
<!-- CSS -->
|
||||||
|
<title>src/fiber_orm/util</title>
|
||||||
|
<link rel="stylesheet" type="text/css" href="../nimdoc.out.css">
|
||||||
|
|
||||||
|
<script type="text/javascript" src="../dochack.js"></script>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
function main() {
|
||||||
|
var pragmaDots = document.getElementsByClassName("pragmadots");
|
||||||
|
for (var i = 0; i < pragmaDots.length; i++) {
|
||||||
|
pragmaDots[i].onclick = function(event) {
|
||||||
|
// Hide tease
|
||||||
|
event.target.parentNode.style.display = "none";
|
||||||
|
// Show actual
|
||||||
|
event.target.parentNode.nextElementSibling.style.display = "inline";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function switchTheme(e) {
|
||||||
|
if (e.target.checked) {
|
||||||
|
document.documentElement.setAttribute('data-theme', 'dark');
|
||||||
|
localStorage.setItem('theme', 'dark');
|
||||||
|
} else {
|
||||||
|
document.documentElement.setAttribute('data-theme', 'light');
|
||||||
|
localStorage.setItem('theme', 'light');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const toggleSwitch = document.querySelector('.theme-switch input[type="checkbox"]');
|
||||||
|
if (toggleSwitch !== null) {
|
||||||
|
toggleSwitch.addEventListener('change', switchTheme, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
var currentTheme = localStorage.getItem('theme');
|
||||||
|
if (!currentTheme && window.matchMedia('(prefers-color-scheme: dark)').matches) {
|
||||||
|
currentTheme = 'dark';
|
||||||
|
}
|
||||||
|
if (currentTheme) {
|
||||||
|
document.documentElement.setAttribute('data-theme', currentTheme);
|
||||||
|
|
||||||
|
if (currentTheme === 'dark' && toggleSwitch !== null) {
|
||||||
|
toggleSwitch.checked = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener('DOMContentLoaded', main);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="document" id="documentId">
|
||||||
|
<div class="container">
|
||||||
|
<h1 class="title">src/fiber_orm/util</h1>
|
||||||
|
<div class="row">
|
||||||
|
<div class="three columns">
|
||||||
|
<div class="theme-switch-wrapper">
|
||||||
|
<label class="theme-switch" for="checkbox">
|
||||||
|
<input type="checkbox" id="checkbox" />
|
||||||
|
<div class="slider round"></div>
|
||||||
|
</label>
|
||||||
|
<em>Dark Mode</em>
|
||||||
|
</div>
|
||||||
|
<div id="global-links">
|
||||||
|
<ul class="simple">
|
||||||
|
<li>
|
||||||
|
<a href="../theindex.html">Index</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div id="searchInputDiv">
|
||||||
|
Search: <input type="text" id="searchInput"
|
||||||
|
onkeyup="search()" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
Group by:
|
||||||
|
<select onchange="groupBy(this.value)">
|
||||||
|
<option value="section">Section</option>
|
||||||
|
<option value="type">Type</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<ul class="simple simple-toc" id="toc-list">
|
||||||
|
<li>
|
||||||
|
<a class="reference reference-toplevel" href="#7" id="57">Types</a>
|
||||||
|
<ul class="simple simple-toc-section">
|
||||||
|
<li><a class="reference" href="#MutateClauses"
|
||||||
|
title="MutateClauses = object
|
||||||
|
columns*: seq[string]
|
||||||
|
placeholders*: seq[string]
|
||||||
|
values*: seq[string]">MutateClauses</a></li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a class="reference reference-toplevel" href="#12" id="62">Procs</a>
|
||||||
|
<ul class="simple simple-toc-section">
|
||||||
|
<ul class="simple nested-toc-section">createParseStmt
|
||||||
|
<li><a class="reference" href="#createParseStmt%2CNimNode%2CNimNode"
|
||||||
|
title="createParseStmt(t, value: NimNode): NimNode">createParseStmt(t, value: NimNode): NimNode</a></li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
<ul class="simple nested-toc-section">dbFormat
|
||||||
|
<li><a class="reference" href="#dbFormat%2CDateTime"
|
||||||
|
title="dbFormat(dt: DateTime): string">dbFormat(dt: DateTime): string</a></li>
|
||||||
|
<li><a class="reference" href="#dbFormat%2Cstring"
|
||||||
|
title="dbFormat(s: string): string">dbFormat(s: string): string</a></li>
|
||||||
|
<li><a class="reference" href="#dbFormat%2CT"
|
||||||
|
title="dbFormat[T](item: T): string">dbFormat[T](item: T): string</a></li>
|
||||||
|
<li><a class="reference" href="#dbFormat%2Cseq%5BT%5D"
|
||||||
|
title="dbFormat[T](list: seq[T]): string">dbFormat[T](list: seq[T]): string</a></li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
<ul class="simple nested-toc-section">dbNameToIdent
|
||||||
|
<li><a class="reference" href="#dbNameToIdent%2Cstring"
|
||||||
|
title="dbNameToIdent(name: string): string">dbNameToIdent(name: string): string</a></li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
<ul class="simple nested-toc-section">identNameToDb
|
||||||
|
<li><a class="reference" href="#identNameToDb%2Cstring"
|
||||||
|
title="identNameToDb(name: string): string">identNameToDb(name: string): string</a></li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
<ul class="simple nested-toc-section">parseDbArray
|
||||||
|
<li><a class="reference" href="#parseDbArray%2Cstring"
|
||||||
|
title="parseDbArray(val: string): seq[string]">parseDbArray(val: string): seq[string]</a></li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
<ul class="simple nested-toc-section">parsePGDatetime
|
||||||
|
<li><a class="reference" href="#parsePGDatetime%2Cstring"
|
||||||
|
title="parsePGDatetime(val: string): DateTime">parsePGDatetime(val: string): DateTime</a></li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
<ul class="simple nested-toc-section">pluralize
|
||||||
|
<li><a class="reference" href="#pluralize%2Cstring"
|
||||||
|
title="pluralize(name: string): string">pluralize(name: string): string</a></li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
<ul class="simple nested-toc-section">tableName
|
||||||
|
<li><a class="reference" href="#tableName%2Ctype"
|
||||||
|
title="tableName(modelType: type): string">tableName(modelType: type): string</a></li>
|
||||||
|
<li><a class="reference" href="#tableName%2CT"
|
||||||
|
title="tableName[T](rec: T): string">tableName[T](rec: T): string</a></li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
<ul class="simple nested-toc-section">typeOfColumn
|
||||||
|
<li><a class="reference" href="#typeOfColumn%2CNimNode%2Cstring"
|
||||||
|
title="typeOfColumn(modelType: NimNode; colName: string): NimNode">typeOfColumn(modelType: NimNode; colName: string): NimNode</a></li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a class="reference reference-toplevel" href="#17" id="67">Macros</a>
|
||||||
|
<ul class="simple simple-toc-section">
|
||||||
|
<ul class="simple nested-toc-section">columnNamesForModel
|
||||||
|
<li><a class="reference" href="#columnNamesForModel.m%2Ctyped"
|
||||||
|
title="columnNamesForModel(modelType: typed): seq[string]">columnNamesForModel(modelType: typed): seq[string]</a></li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
<ul class="simple nested-toc-section">listFields
|
||||||
|
<li><a class="reference" href="#listFields.m%2Ctyped"
|
||||||
|
title="listFields(t: typed): untyped">listFields(t: typed): untyped</a></li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
<ul class="simple nested-toc-section">modelName
|
||||||
|
<li><a class="reference" href="#modelName.m"
|
||||||
|
title="modelName(model: object): string">modelName(model: object): string</a></li>
|
||||||
|
<li><a class="reference" href="#modelName.m%2Ctype"
|
||||||
|
title="modelName(modelType: type): string">modelName(modelType: type): string</a></li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
<ul class="simple nested-toc-section">populateMutateClauses
|
||||||
|
<li><a class="reference" href="#populateMutateClauses.m%2Ctyped%2Cbool%2CMutateClauses"
|
||||||
|
title="populateMutateClauses(t: typed; newRecord: bool; mc: var MutateClauses): untyped">populateMutateClauses(t: typed; newRecord: bool; mc: var MutateClauses): untyped</a></li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
<ul class="simple nested-toc-section">rowToModel
|
||||||
|
<li><a class="reference" href="#rowToModel.m%2Ctyped%2Cseq%5Bstring%5D"
|
||||||
|
title="rowToModel(modelType: typed; row: seq[string]): untyped">rowToModel(modelType: typed; row: seq[string]): untyped</a></li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a class="reference reference-toplevel" href="#18" id="68">Templates</a>
|
||||||
|
<ul class="simple simple-toc-section">
|
||||||
|
<ul class="simple nested-toc-section">walkFieldDefs
|
||||||
|
<li><a class="reference" href="#walkFieldDefs.t%2CNimNode%2Cuntyped"
|
||||||
|
title="walkFieldDefs(t: NimNode; body: untyped)">walkFieldDefs(t: NimNode; body: untyped)</a></li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<a
|
||||||
|
href="https://github.com/jdbernard/fiber-orm/tree/version-1-6/src/fiber_orm/util.nim#L1"
|
||||||
|
class="link-seesrc" target="_blank">Source</a>
|
||||||
|
<a href="https://github.com/jdbernard/fiber-orm/edit/devel/src/fiber_orm/util.nim#L1" class="link-seesrc" target="_blank" >Edit</a>
|
||||||
|
|
||||||
|
<div class="nine columns" id="content">
|
||||||
|
<div id="tocRoot"></div>
|
||||||
|
|
||||||
|
<p class="module-desc">Utility methods used internally by Fiber ORM.</p>
|
||||||
|
<div class="section" id="7">
|
||||||
|
<h1><a class="toc-backref" href="#7">Types</a></h1>
|
||||||
|
<dl class="item">
|
||||||
|
<div id="MutateClauses">
|
||||||
|
<dt><pre><a href="util.html#MutateClauses"><span class="Identifier">MutateClauses</span></a> <span class="Other">=</span> <span class="Keyword">object</span>
|
||||||
|
<span class="Identifier">columns</span><span class="Operator">*</span><span class="Other">:</span> <span class="Identifier">seq</span><span class="Other">[</span><span class="Identifier">string</span><span class="Other">]</span>
|
||||||
|
<span class="Identifier">placeholders</span><span class="Operator">*</span><span class="Other">:</span> <span class="Identifier">seq</span><span class="Other">[</span><span class="Identifier">string</span><span class="Other">]</span>
|
||||||
|
<span class="Identifier">values</span><span class="Operator">*</span><span class="Other">:</span> <span class="Identifier">seq</span><span class="Other">[</span><span class="Identifier">string</span><span class="Other">]</span>
|
||||||
|
</pre></dt>
|
||||||
|
<dd>
|
||||||
|
|
||||||
|
Data structure to hold information about the clauses that should be added to a query. How these clauses are used will depend on the query. This common data structure provides the information needed to create WHERE clauses, UPDATE clauses, etc.
|
||||||
|
<a
|
||||||
|
href="https://github.com/jdbernard/fiber-orm/tree/version-1-6/src/fiber_orm/util.nim#L12"
|
||||||
|
class="link-seesrc" target="_blank">Source</a>
|
||||||
|
<a href="https://github.com/jdbernard/fiber-orm/edit/devel/src/fiber_orm/util.nim#L12" class="link-seesrc" target="_blank" >Edit</a>
|
||||||
|
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</dl></div>
|
||||||
|
<div class="section" id="12">
|
||||||
|
<h1><a class="toc-backref" href="#12">Procs</a></h1>
|
||||||
|
<dl class="item">
|
||||||
|
<div id="createParseStmt,NimNode,NimNode">
|
||||||
|
<dt><pre><span class="Keyword">proc</span> <a href="#createParseStmt%2CNimNode%2CNimNode"><span class="Identifier">createParseStmt</span></a><span class="Other">(</span><span class="Identifier">t</span><span class="Other">,</span> <span class="Identifier">value</span><span class="Other">:</span> <span class="Identifier">NimNode</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">NimNode</span> {.<span><span class="Other pragmadots">...</span></span><span class="pragmawrap"><span class="Identifier">raises</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span><span class="Other">,</span> <span class="Identifier">tags</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span></span>.}</pre></dt>
|
||||||
|
<dd>
|
||||||
|
|
||||||
|
Utility method to create the Nim cod required to parse a value coming from the a database query. This is used by functions like <tt class="docutils literal"><span class="pre"><span class="Identifier">rowToModel</span></span></tt> to parse the dataabase columns into the Nim object fields.
|
||||||
|
<a
|
||||||
|
href="https://github.com/jdbernard/fiber-orm/tree/version-1-6/src/fiber_orm/util.nim#L190"
|
||||||
|
class="link-seesrc" target="_blank">Source</a>
|
||||||
|
<a href="https://github.com/jdbernard/fiber-orm/edit/devel/src/fiber_orm/util.nim#L190" class="link-seesrc" target="_blank" >Edit</a>
|
||||||
|
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
<div id="dbFormat,DateTime">
|
||||||
|
<dt><pre><span class="Keyword">proc</span> <a href="#dbFormat%2CDateTime"><span class="Identifier">dbFormat</span></a><span class="Other">(</span><span class="Identifier">dt</span><span class="Other">:</span> <span class="Identifier">DateTime</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">string</span> {.<span><span class="Other pragmadots">...</span></span><span class="pragmawrap"><span class="Identifier">raises</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span><span class="Other">,</span> <span class="Identifier">tags</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span></span>.}</pre></dt>
|
||||||
|
<dd>
|
||||||
|
|
||||||
|
Format a DateTime for inclusion in a SQL Query.
|
||||||
|
<a
|
||||||
|
href="https://github.com/jdbernard/fiber-orm/tree/version-1-6/src/fiber_orm/util.nim#L75"
|
||||||
|
class="link-seesrc" target="_blank">Source</a>
|
||||||
|
<a href="https://github.com/jdbernard/fiber-orm/edit/devel/src/fiber_orm/util.nim#L75" class="link-seesrc" target="_blank" >Edit</a>
|
||||||
|
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
<div id="dbFormat,string">
|
||||||
|
<dt><pre><span class="Keyword">proc</span> <a href="#dbFormat%2Cstring"><span class="Identifier">dbFormat</span></a><span class="Other">(</span><span class="Identifier">s</span><span class="Other">:</span> <span class="Identifier">string</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">string</span> {.<span><span class="Other pragmadots">...</span></span><span class="pragmawrap"><span class="Identifier">raises</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span><span class="Other">,</span> <span class="Identifier">tags</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span></span>.}</pre></dt>
|
||||||
|
<dd>
|
||||||
|
|
||||||
|
Format a string for inclusion in a SQL Query.
|
||||||
|
<a
|
||||||
|
href="https://github.com/jdbernard/fiber-orm/tree/version-1-6/src/fiber_orm/util.nim#L71"
|
||||||
|
class="link-seesrc" target="_blank">Source</a>
|
||||||
|
<a href="https://github.com/jdbernard/fiber-orm/edit/devel/src/fiber_orm/util.nim#L71" class="link-seesrc" target="_blank" >Edit</a>
|
||||||
|
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
<div id="dbFormat,T">
|
||||||
|
<dt><pre><span class="Keyword">proc</span> <a href="#dbFormat%2CT"><span class="Identifier">dbFormat</span></a><span class="Other">[</span><span class="Identifier">T</span><span class="Other">]</span><span class="Other">(</span><span class="Identifier">item</span><span class="Other">:</span> <span class="Identifier">T</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">string</span></pre></dt>
|
||||||
|
<dd>
|
||||||
|
|
||||||
|
For all other types, fall back on a defined <tt class="docutils literal"><span class="pre"><span class="Operator">$</span></span></tt> function to create a string version of the value we can include in an SQL query>
|
||||||
|
<a
|
||||||
|
href="https://github.com/jdbernard/fiber-orm/tree/version-1-6/src/fiber_orm/util.nim#L83"
|
||||||
|
class="link-seesrc" target="_blank">Source</a>
|
||||||
|
<a href="https://github.com/jdbernard/fiber-orm/edit/devel/src/fiber_orm/util.nim#L83" class="link-seesrc" target="_blank" >Edit</a>
|
||||||
|
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
<div id="dbFormat,seq[T]">
|
||||||
|
<dt><pre><span class="Keyword">proc</span> <a href="#dbFormat%2Cseq%5BT%5D"><span class="Identifier">dbFormat</span></a><span class="Other">[</span><span class="Identifier">T</span><span class="Other">]</span><span class="Other">(</span><span class="Identifier">list</span><span class="Other">:</span> <span class="Identifier">seq</span><span class="Other">[</span><span class="Identifier">T</span><span class="Other">]</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">string</span></pre></dt>
|
||||||
|
<dd>
|
||||||
|
|
||||||
|
Format a <tt class="docutils literal"><span class="pre"><span class="Identifier">seq</span></span></tt> for inclusion in a SQL Query.
|
||||||
|
<a
|
||||||
|
href="https://github.com/jdbernard/fiber-orm/tree/version-1-6/src/fiber_orm/util.nim#L79"
|
||||||
|
class="link-seesrc" target="_blank">Source</a>
|
||||||
|
<a href="https://github.com/jdbernard/fiber-orm/edit/devel/src/fiber_orm/util.nim#L79" class="link-seesrc" target="_blank" >Edit</a>
|
||||||
|
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
<div id="dbNameToIdent,string">
|
||||||
|
<dt><pre><span class="Keyword">proc</span> <a href="#dbNameToIdent%2Cstring"><span class="Identifier">dbNameToIdent</span></a><span class="Other">(</span><span class="Identifier">name</span><span class="Other">:</span> <span class="Identifier">string</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">string</span> {.<span><span class="Other pragmadots">...</span></span><span class="pragmawrap"><span class="Identifier">raises</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span><span class="Other">,</span> <span class="Identifier">tags</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span></span>.}</pre></dt>
|
||||||
|
<dd>
|
||||||
|
|
||||||
|
Map a DB name to a Nim identifier name. See the <a class="reference external" href="../fiber_orm.html">rules for name mapping</a>
|
||||||
|
<a
|
||||||
|
href="https://github.com/jdbernard/fiber-orm/tree/version-1-6/src/fiber_orm/util.nim#L58"
|
||||||
|
class="link-seesrc" target="_blank">Source</a>
|
||||||
|
<a href="https://github.com/jdbernard/fiber-orm/edit/devel/src/fiber_orm/util.nim#L58" class="link-seesrc" target="_blank" >Edit</a>
|
||||||
|
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
<div id="identNameToDb,string">
|
||||||
|
<dt><pre><span class="Keyword">proc</span> <a href="#identNameToDb%2Cstring"><span class="Identifier">identNameToDb</span></a><span class="Other">(</span><span class="Identifier">name</span><span class="Other">:</span> <span class="Identifier">string</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">string</span> {.<span><span class="Other pragmadots">...</span></span><span class="pragmawrap"><span class="Identifier">raises</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span><span class="Other">,</span> <span class="Identifier">tags</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span></span>.}</pre></dt>
|
||||||
|
<dd>
|
||||||
|
|
||||||
|
<p>Map a Nim identifier name to a DB name. See the <a class="reference external" href="../fiber_orm.html">rules for name mapping</a></p>
|
||||||
|
<p>TODO link above</p>
|
||||||
|
|
||||||
|
<a
|
||||||
|
href="https://github.com/jdbernard/fiber-orm/tree/version-1-6/src/fiber_orm/util.nim#L37"
|
||||||
|
class="link-seesrc" target="_blank">Source</a>
|
||||||
|
<a href="https://github.com/jdbernard/fiber-orm/edit/devel/src/fiber_orm/util.nim#L37" class="link-seesrc" target="_blank" >Edit</a>
|
||||||
|
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
<div id="parseDbArray,string">
|
||||||
|
<dt><pre><span class="Keyword">proc</span> <a href="#parseDbArray%2Cstring"><span class="Identifier">parseDbArray</span></a><span class="Other">(</span><span class="Identifier">val</span><span class="Other">:</span> <span class="Identifier">string</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">seq</span><span class="Other">[</span><span class="Identifier">string</span><span class="Other">]</span> {.<span><span class="Other pragmadots">...</span></span><span class="pragmawrap"><span class="Identifier">raises</span><span class="Other">:</span> <span class="Other">[</span><span class="Identifier">ValueError</span><span class="Other">]</span><span class="Other">,</span> <span class="Identifier">tags</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span></span>.}</pre></dt>
|
||||||
|
<dd>
|
||||||
|
|
||||||
|
Parse a Postgres array column into a Nim seq[string]
|
||||||
|
<a
|
||||||
|
href="https://github.com/jdbernard/fiber-orm/tree/version-1-6/src/fiber_orm/util.nim#L131"
|
||||||
|
class="link-seesrc" target="_blank">Source</a>
|
||||||
|
<a href="https://github.com/jdbernard/fiber-orm/edit/devel/src/fiber_orm/util.nim#L131" class="link-seesrc" target="_blank" >Edit</a>
|
||||||
|
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
<div id="parsePGDatetime,string">
|
||||||
|
<dt><pre><span class="Keyword">proc</span> <a href="#parsePGDatetime%2Cstring"><span class="Identifier">parsePGDatetime</span></a><span class="Other">(</span><span class="Identifier">val</span><span class="Other">:</span> <span class="Identifier">string</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">DateTime</span> {.<span><span class="Other pragmadots">...</span></span><span class="pragmawrap"><span class="Identifier">raises</span><span class="Other">:</span> <span class="Other">[</span><span class="Identifier">KeyError</span><span class="Other">,</span> <span class="Identifier">SyntaxError</span><span class="Other">,</span>
|
||||||
|
<span class="Identifier">StudyError</span><span class="Other">,</span> <span class="Identifier">ValueError</span><span class="Other">,</span> <span class="Identifier">RegexInternalError</span><span class="Other">,</span> <span class="Identifier">InvalidUnicodeError</span><span class="Other">]</span><span class="Other">,</span>
|
||||||
|
<span class="Identifier">tags</span><span class="Other">:</span> <span class="Other">[</span><span class="Identifier">TimeEffect</span><span class="Other">]</span></span>.}</pre></dt>
|
||||||
|
<dd>
|
||||||
|
|
||||||
|
Parse a Postgres datetime value into a Nim DateTime object.
|
||||||
|
<a
|
||||||
|
href="https://github.com/jdbernard/fiber-orm/tree/version-1-6/src/fiber_orm/util.nim#L91"
|
||||||
|
class="link-seesrc" target="_blank">Source</a>
|
||||||
|
<a href="https://github.com/jdbernard/fiber-orm/edit/devel/src/fiber_orm/util.nim#L91" class="link-seesrc" target="_blank" >Edit</a>
|
||||||
|
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
<div id="pluralize,string">
|
||||||
|
<dt><pre><span class="Keyword">proc</span> <a href="#pluralize%2Cstring"><span class="Identifier">pluralize</span></a><span class="Other">(</span><span class="Identifier">name</span><span class="Other">:</span> <span class="Identifier">string</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">string</span> {.<span><span class="Other pragmadots">...</span></span><span class="pragmawrap"><span class="Identifier">raises</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span><span class="Other">,</span> <span class="Identifier">tags</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span></span>.}</pre></dt>
|
||||||
|
<dd>
|
||||||
|
|
||||||
|
Return the plural form of the given name.
|
||||||
|
<a
|
||||||
|
href="https://github.com/jdbernard/fiber-orm/tree/version-1-6/src/fiber_orm/util.nim#L23"
|
||||||
|
class="link-seesrc" target="_blank">Source</a>
|
||||||
|
<a href="https://github.com/jdbernard/fiber-orm/edit/devel/src/fiber_orm/util.nim#L23" class="link-seesrc" target="_blank" >Edit</a>
|
||||||
|
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
<div id="tableName,type">
|
||||||
|
<dt><pre><span class="Keyword">proc</span> <a href="#tableName%2Ctype"><span class="Identifier">tableName</span></a><span class="Other">(</span><span class="Identifier">modelType</span><span class="Other">:</span> <span class="Identifier">type</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">string</span></pre></dt>
|
||||||
|
<dd>
|
||||||
|
|
||||||
|
Get the <a class="reference external" href="../fiber_orm.html">table name</a> for a given <a class="reference external" href="../fiber_orm.html#objectminusrelational-modeling-model-class">model class</a>
|
||||||
|
<a
|
||||||
|
href="https://github.com/jdbernard/fiber-orm/tree/version-1-6/src/fiber_orm/util.nim#L63"
|
||||||
|
class="link-seesrc" target="_blank">Source</a>
|
||||||
|
<a href="https://github.com/jdbernard/fiber-orm/edit/devel/src/fiber_orm/util.nim#L63" class="link-seesrc" target="_blank" >Edit</a>
|
||||||
|
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
<div id="tableName,T">
|
||||||
|
<dt><pre><span class="Keyword">proc</span> <a href="#tableName%2CT"><span class="Identifier">tableName</span></a><span class="Other">[</span><span class="Identifier">T</span><span class="Other">]</span><span class="Other">(</span><span class="Identifier">rec</span><span class="Other">:</span> <span class="Identifier">T</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">string</span></pre></dt>
|
||||||
|
<dd>
|
||||||
|
|
||||||
|
Get the <a class="reference external" href="../fiber_orm.html">table name</a> for a given record.
|
||||||
|
<a
|
||||||
|
href="https://github.com/jdbernard/fiber-orm/tree/version-1-6/src/fiber_orm/util.nim#L67"
|
||||||
|
class="link-seesrc" target="_blank">Source</a>
|
||||||
|
<a href="https://github.com/jdbernard/fiber-orm/edit/devel/src/fiber_orm/util.nim#L67" class="link-seesrc" target="_blank" >Edit</a>
|
||||||
|
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
<div id="typeOfColumn,NimNode,string">
|
||||||
|
<dt><pre><span class="Keyword">proc</span> <a href="#typeOfColumn%2CNimNode%2Cstring"><span class="Identifier">typeOfColumn</span></a><span class="Other">(</span><span class="Identifier">modelType</span><span class="Other">:</span> <span class="Identifier">NimNode</span><span class="Other">;</span> <span class="Identifier">colName</span><span class="Other">:</span> <span class="Identifier">string</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">NimNode</span> {.
|
||||||
|
<span><span class="Other pragmadots">...</span></span><span class="pragmawrap"><span class="Identifier">raises</span><span class="Other">:</span> <span class="Other">[</span><span class="Identifier">Exception</span><span class="Other">]</span><span class="Other">,</span> <span class="Identifier">tags</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span></span>.}</pre></dt>
|
||||||
|
<dd>
|
||||||
|
|
||||||
|
Given a model type and a column name, return the Nim type for that column.
|
||||||
|
<a
|
||||||
|
href="https://github.com/jdbernard/fiber-orm/tree/version-1-6/src/fiber_orm/util.nim#L308"
|
||||||
|
class="link-seesrc" target="_blank">Source</a>
|
||||||
|
<a href="https://github.com/jdbernard/fiber-orm/edit/devel/src/fiber_orm/util.nim#L308" class="link-seesrc" target="_blank" >Edit</a>
|
||||||
|
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</dl></div>
|
||||||
|
<div class="section" id="17">
|
||||||
|
<h1><a class="toc-backref" href="#17">Macros</a></h1>
|
||||||
|
<dl class="item">
|
||||||
|
<div id="columnNamesForModel.m,typed">
|
||||||
|
<dt><pre><span class="Keyword">macro</span> <a href="#columnNamesForModel.m%2Ctyped"><span class="Identifier">columnNamesForModel</span></a><span class="Other">(</span><span class="Identifier">modelType</span><span class="Other">:</span> <span class="Identifier">typed</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">seq</span><span class="Other">[</span><span class="Identifier">string</span><span class="Other">]</span></pre></dt>
|
||||||
|
<dd>
|
||||||
|
|
||||||
|
Return the column names corresponding to the the fields of the given <a class="reference external" href="../fiber_orm.html#objectminusrelational-modeling-model-class">model class</a>
|
||||||
|
<a
|
||||||
|
href="https://github.com/jdbernard/fiber-orm/tree/version-1-6/src/fiber_orm/util.nim#L274"
|
||||||
|
class="link-seesrc" target="_blank">Source</a>
|
||||||
|
<a href="https://github.com/jdbernard/fiber-orm/edit/devel/src/fiber_orm/util.nim#L274" class="link-seesrc" target="_blank" >Edit</a>
|
||||||
|
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
<div id="listFields.m,typed">
|
||||||
|
<dt><pre><span class="Keyword">macro</span> <a href="#listFields.m%2Ctyped"><span class="Identifier">listFields</span></a><span class="Other">(</span><span class="Identifier">t</span><span class="Other">:</span> <span class="Identifier">typed</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">untyped</span></pre></dt>
|
||||||
|
<dd>
|
||||||
|
|
||||||
|
|
||||||
|
<a
|
||||||
|
href="https://github.com/jdbernard/fiber-orm/tree/version-1-6/src/fiber_orm/util.nim#L300"
|
||||||
|
class="link-seesrc" target="_blank">Source</a>
|
||||||
|
<a href="https://github.com/jdbernard/fiber-orm/edit/devel/src/fiber_orm/util.nim#L300" class="link-seesrc" target="_blank" >Edit</a>
|
||||||
|
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
<div id="modelName.m">
|
||||||
|
<dt><pre><span class="Keyword">macro</span> <a href="#modelName.m"><span class="Identifier">modelName</span></a><span class="Other">(</span><span class="Identifier">model</span><span class="Other">:</span> <span class="Keyword">object</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">string</span></pre></dt>
|
||||||
|
<dd>
|
||||||
|
|
||||||
|
For a given concrete record object, return the name of the <a class="reference external" href="../fiber_orm.html#objectminusrelational-modeling-model-class">model class</a>
|
||||||
|
<a
|
||||||
|
href="https://github.com/jdbernard/fiber-orm/tree/version-1-6/src/fiber_orm/util.nim#L29"
|
||||||
|
class="link-seesrc" target="_blank">Source</a>
|
||||||
|
<a href="https://github.com/jdbernard/fiber-orm/edit/devel/src/fiber_orm/util.nim#L29" class="link-seesrc" target="_blank" >Edit</a>
|
||||||
|
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
<div id="modelName.m,type">
|
||||||
|
<dt><pre><span class="Keyword">macro</span> <a href="#modelName.m%2Ctype"><span class="Identifier">modelName</span></a><span class="Other">(</span><span class="Identifier">modelType</span><span class="Other">:</span> <span class="Identifier">type</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">string</span></pre></dt>
|
||||||
|
<dd>
|
||||||
|
|
||||||
|
Get the name of a given <a class="reference external" href="../fiber_orm.html#objectminusrelational-modeling-model-class">model class</a>
|
||||||
|
<a
|
||||||
|
href="https://github.com/jdbernard/fiber-orm/tree/version-1-6/src/fiber_orm/util.nim#L33"
|
||||||
|
class="link-seesrc" target="_blank">Source</a>
|
||||||
|
<a href="https://github.com/jdbernard/fiber-orm/edit/devel/src/fiber_orm/util.nim#L33" class="link-seesrc" target="_blank" >Edit</a>
|
||||||
|
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
<div id="populateMutateClauses.m,typed,bool,MutateClauses">
|
||||||
|
<dt><pre><span class="Keyword">macro</span> <a href="#populateMutateClauses.m%2Ctyped%2Cbool%2CMutateClauses"><span class="Identifier">populateMutateClauses</span></a><span class="Other">(</span><span class="Identifier">t</span><span class="Other">:</span> <span class="Identifier">typed</span><span class="Other">;</span> <span class="Identifier">newRecord</span><span class="Other">:</span> <span class="Identifier">bool</span><span class="Other">;</span> <span class="Identifier">mc</span><span class="Other">:</span> <span class="Keyword">var</span> <a href="util.html#MutateClauses"><span class="Identifier">MutateClauses</span></a><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">untyped</span></pre></dt>
|
||||||
|
<dd>
|
||||||
|
|
||||||
|
Given a record type, create the datastructure used to generate SQL clauses for the fields of this record type.
|
||||||
|
<a
|
||||||
|
href="https://github.com/jdbernard/fiber-orm/tree/version-1-6/src/fiber_orm/util.nim#L330"
|
||||||
|
class="link-seesrc" target="_blank">Source</a>
|
||||||
|
<a href="https://github.com/jdbernard/fiber-orm/edit/devel/src/fiber_orm/util.nim#L330" class="link-seesrc" target="_blank" >Edit</a>
|
||||||
|
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
<div id="rowToModel.m,typed,seq[string]">
|
||||||
|
<dt><pre><span class="Keyword">macro</span> <a href="#rowToModel.m%2Ctyped%2Cseq%5Bstring%5D"><span class="Identifier">rowToModel</span></a><span class="Other">(</span><span class="Identifier">modelType</span><span class="Other">:</span> <span class="Identifier">typed</span><span class="Other">;</span> <span class="Identifier">row</span><span class="Other">:</span> <span class="Identifier">seq</span><span class="Other">[</span><span class="Identifier">string</span><span class="Other">]</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">untyped</span></pre></dt>
|
||||||
|
<dd>
|
||||||
|
|
||||||
|
Return a new Nim model object of type <tt class="docutils literal"><span class="pre"><span class="Identifier">modelType</span></span></tt> populated with the values returned in the given database <tt class="docutils literal"><span class="pre"><span class="Identifier">row</span></span></tt>
|
||||||
|
<a
|
||||||
|
href="https://github.com/jdbernard/fiber-orm/tree/version-1-6/src/fiber_orm/util.nim#L284"
|
||||||
|
class="link-seesrc" target="_blank">Source</a>
|
||||||
|
<a href="https://github.com/jdbernard/fiber-orm/edit/devel/src/fiber_orm/util.nim#L284" class="link-seesrc" target="_blank" >Edit</a>
|
||||||
|
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</dl></div>
|
||||||
|
<div class="section" id="18">
|
||||||
|
<h1><a class="toc-backref" href="#18">Templates</a></h1>
|
||||||
|
<dl class="item">
|
||||||
|
<div id="walkFieldDefs.t,NimNode,untyped">
|
||||||
|
<dt><pre><span class="Keyword">template</span> <a href="#walkFieldDefs.t%2CNimNode%2Cuntyped"><span class="Identifier">walkFieldDefs</span></a><span class="Other">(</span><span class="Identifier">t</span><span class="Other">:</span> <span class="Identifier">NimNode</span><span class="Other">;</span> <span class="Identifier">body</span><span class="Other">:</span> <span class="Identifier">untyped</span><span class="Other">)</span></pre></dt>
|
||||||
|
<dd>
|
||||||
|
|
||||||
|
Iterate over every field of the given Nim object, yielding and defining <tt class="docutils literal"><span class="pre"><span class="Identifier">fieldIdent</span></span></tt> and <tt class="docutils literal"><span class="pre"><span class="Identifier">fieldType</span></span></tt>, the name of the field as a Nim Ident node and the type of the field as a Nim Type node respectively.
|
||||||
|
<a
|
||||||
|
href="https://github.com/jdbernard/fiber-orm/tree/version-1-6/src/fiber_orm/util.nim#L251"
|
||||||
|
class="link-seesrc" target="_blank">Source</a>
|
||||||
|
<a href="https://github.com/jdbernard/fiber-orm/edit/devel/src/fiber_orm/util.nim#L251" class="link-seesrc" target="_blank" >Edit</a>
|
||||||
|
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</dl></div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="twelve-columns footer">
|
||||||
|
<span class="nim-sprite"></span>
|
||||||
|
<br/>
|
||||||
|
<small style="color: var(--hint);">Made with Nim. Generated: 2022-09-04 02:31:20 UTC</small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
21
docs/fiber_orm/util.idx
Normal file
21
docs/fiber_orm/util.idx
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
MutateClauses fiber_orm/util.html#MutateClauses util: MutateClauses
|
||||||
|
pluralize fiber_orm/util.html#pluralize,string util: pluralize(name: string): string
|
||||||
|
modelName fiber_orm/util.html#modelName.m util: modelName(model: object): string
|
||||||
|
modelName fiber_orm/util.html#modelName.m,type util: modelName(modelType: type): string
|
||||||
|
identNameToDb fiber_orm/util.html#identNameToDb,string util: identNameToDb(name: string): string
|
||||||
|
dbNameToIdent fiber_orm/util.html#dbNameToIdent,string util: dbNameToIdent(name: string): string
|
||||||
|
tableName fiber_orm/util.html#tableName,type util: tableName(modelType: type): string
|
||||||
|
tableName fiber_orm/util.html#tableName,T util: tableName[T](rec: T): string
|
||||||
|
dbFormat fiber_orm/util.html#dbFormat,string util: dbFormat(s: string): string
|
||||||
|
dbFormat fiber_orm/util.html#dbFormat,DateTime util: dbFormat(dt: DateTime): string
|
||||||
|
dbFormat fiber_orm/util.html#dbFormat,seq[T] util: dbFormat[T](list: seq[T]): string
|
||||||
|
dbFormat fiber_orm/util.html#dbFormat,T util: dbFormat[T](item: T): string
|
||||||
|
parsePGDatetime fiber_orm/util.html#parsePGDatetime,string util: parsePGDatetime(val: string): DateTime
|
||||||
|
parseDbArray fiber_orm/util.html#parseDbArray,string util: parseDbArray(val: string): seq[string]
|
||||||
|
createParseStmt fiber_orm/util.html#createParseStmt,NimNode,NimNode util: createParseStmt(t, value: NimNode): NimNode
|
||||||
|
walkFieldDefs fiber_orm/util.html#walkFieldDefs.t,NimNode,untyped util: walkFieldDefs(t: NimNode; body: untyped)
|
||||||
|
columnNamesForModel fiber_orm/util.html#columnNamesForModel.m,typed util: columnNamesForModel(modelType: typed): seq[string]
|
||||||
|
rowToModel fiber_orm/util.html#rowToModel.m,typed,seq[string] util: rowToModel(modelType: typed; row: seq[string]): untyped
|
||||||
|
listFields fiber_orm/util.html#listFields.m,typed util: listFields(t: typed): untyped
|
||||||
|
typeOfColumn fiber_orm/util.html#typeOfColumn,NimNode,string util: typeOfColumn(modelType: NimNode; colName: string): NimNode
|
||||||
|
populateMutateClauses fiber_orm/util.html#populateMutateClauses.m,typed,bool,MutateClauses util: populateMutateClauses(t: typed; newRecord: bool; mc: var MutateClauses): untyped
|
619
docs/index.html
Normal file
619
docs/index.html
Normal file
@ -0,0 +1,619 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
||||||
|
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||||
|
<!-- This file is generated by Nim. -->
|
||||||
|
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||||
|
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
|
||||||
|
<!-- Favicon -->
|
||||||
|
<link rel="shortcut icon" href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAUAAAAF////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAIAAABbAAAAlQAAAKIAAACbAAAAmwAAAKIAAACVAAAAWwAAAAL///8A////AP///wD///8A////AAAAABQAAADAAAAAYwAAAA3///8A////AP///wD///8AAAAADQAAAGMAAADAAAAAFP///wD///8A////AP///wAAAACdAAAAOv///wD///8A////AP///wD///8A////AP///wD///8AAAAAOgAAAJ3///8A////AP///wAAAAAnAAAAcP///wAAAAAoAAAASv///wD///8A////AP///wAAAABKAAAAKP///wAAAABwAAAAJ////wD///8AAAAAgQAAABwAAACIAAAAkAAAAJMAAACtAAAAFQAAABUAAACtAAAAkwAAAJAAAACIAAAAHAAAAIH///8A////AAAAAKQAAACrAAAAaP///wD///8AAAAARQAAANIAAADSAAAARf///wD///8AAAAAaAAAAKsAAACk////AAAAADMAAACcAAAAnQAAABj///8A////AP///wAAAAAYAAAAGP///wD///8A////AAAAABgAAACdAAAAnAAAADMAAAB1AAAAwwAAAP8AAADpAAAAsQAAAE4AAAAb////AP///wAAAAAbAAAATgAAALEAAADpAAAA/wAAAMMAAAB1AAAAtwAAAOkAAAD/AAAA/wAAAP8AAADvAAAA3gAAAN4AAADeAAAA3gAAAO8AAAD/AAAA/wAAAP8AAADpAAAAtwAAAGUAAAA/AAAA3wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAADfAAAAPwAAAGX///8A////AAAAAEgAAADtAAAAvwAAAL0AAADGAAAA7wAAAO8AAADGAAAAvQAAAL8AAADtAAAASP///wD///8A////AP///wD///8AAAAAO////wD///8A////AAAAAIcAAACH////AP///wD///8AAAAAO////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A//8AAP//AAD4HwAA7/cAAN/7AAD//wAAoYUAAJ55AACf+QAAh+EAAAAAAADAAwAA4AcAAP5/AAD//wAA//8AAA=="/>
|
||||||
|
<link rel="icon" type="image/png" sizes="32x32" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAA3XAAAN1wFCKJt4AAAAB3RJTUUH4QQQEwksSS9ZWwAAAk1JREFUWMPtll2ITVEUx39nn/O7Y5qR8f05wtCUUr6ZIS++8pEnkZInPImneaCQ5METNdOkeFBKUhMPRIkHKfEuUZSUlGlKPN2TrgfncpvmnntnmlEyq1Z7t89/rf9a6+y99oZxGZf/XeIq61EdtgKXgdXA0xrYAvBjOIF1AI9zvjcC74BSpndrJPkBWDScTF8Aa4E3wDlgHbASaANmVqlcCnwHvgDvgVfAJ+AikAAvgfVZwLnSVZHZaOuKoQi3ZOMi4NkYkpe1p4J7A8BpYAD49hfIy/oqG0+hLomiKP2L5L+1ubn5115S+3OAn4EnwBlgMzCjyt6ZAnQCJ4A7wOs88iRJHvw50HoujuPBoCKwHWiosy8MdfZnAdcHk8dxXFJ3VQbQlCTJvRBCGdRbD4M6uc5glpY3eAihpN5S5w12diSEcCCEcKUO4ljdr15T76ur1FDDLIQQ3qv71EdDOe3Kxj3leRXyk+pxdWnFWod6Wt2bY3de3aSuUHcPBVimHs7mK9WrmeOF6lR1o9qnzskh2ar2qm1qizpfXaPeVGdlmGN5pb09qMxz1Xb1kLqgzn1RyH7JUXW52lr5e/Kqi9qpto7V1atuUzfnARrV7jEib1T76gG2qxdGmXyiekkt1GswPTtek0aBfJp6YySGBfWg2tPQ0FAYgf1stUfdmdcjarbYJEniKIq6gY/Aw+zWHAC+p2labGpqiorFYgGYCEzN7oQdQClN07O1/EfDyGgC0ALMBdYAi4FyK+4H3gLPsxfR1zRNi+NP7nH5J+QntnXe5B5mpfQAAAAASUVORK5CYII=">
|
||||||
|
|
||||||
|
<!-- Google fonts -->
|
||||||
|
<link href='https://fonts.googleapis.com/css?family=Lato:400,600,900' rel='stylesheet' type='text/css'/>
|
||||||
|
<link href='https://fonts.googleapis.com/css?family=Source+Code+Pro:400,500,600' rel='stylesheet' type='text/css'/>
|
||||||
|
|
||||||
|
<!-- CSS -->
|
||||||
|
<title>src/fiber_orm</title>
|
||||||
|
<link rel="stylesheet" type="text/css" href="nimdoc.out.css">
|
||||||
|
|
||||||
|
<script type="text/javascript" src="dochack.js"></script>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
function main() {
|
||||||
|
var pragmaDots = document.getElementsByClassName("pragmadots");
|
||||||
|
for (var i = 0; i < pragmaDots.length; i++) {
|
||||||
|
pragmaDots[i].onclick = function(event) {
|
||||||
|
// Hide tease
|
||||||
|
event.target.parentNode.style.display = "none";
|
||||||
|
// Show actual
|
||||||
|
event.target.parentNode.nextElementSibling.style.display = "inline";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function switchTheme(e) {
|
||||||
|
if (e.target.checked) {
|
||||||
|
document.documentElement.setAttribute('data-theme', 'dark');
|
||||||
|
localStorage.setItem('theme', 'dark');
|
||||||
|
} else {
|
||||||
|
document.documentElement.setAttribute('data-theme', 'light');
|
||||||
|
localStorage.setItem('theme', 'light');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const toggleSwitch = document.querySelector('.theme-switch input[type="checkbox"]');
|
||||||
|
if (toggleSwitch !== null) {
|
||||||
|
toggleSwitch.addEventListener('change', switchTheme, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
var currentTheme = localStorage.getItem('theme');
|
||||||
|
if (!currentTheme && window.matchMedia('(prefers-color-scheme: dark)').matches) {
|
||||||
|
currentTheme = 'dark';
|
||||||
|
}
|
||||||
|
if (currentTheme) {
|
||||||
|
document.documentElement.setAttribute('data-theme', currentTheme);
|
||||||
|
|
||||||
|
if (currentTheme === 'dark' && toggleSwitch !== null) {
|
||||||
|
toggleSwitch.checked = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener('DOMContentLoaded', main);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="document" id="documentId">
|
||||||
|
<div class="container">
|
||||||
|
<h1 class="title">src/fiber_orm</h1>
|
||||||
|
<div class="row">
|
||||||
|
<div class="three columns">
|
||||||
|
<div class="theme-switch-wrapper">
|
||||||
|
<label class="theme-switch" for="checkbox">
|
||||||
|
<input type="checkbox" id="checkbox" />
|
||||||
|
<div class="slider round"></div>
|
||||||
|
</label>
|
||||||
|
<em>Dark Mode</em>
|
||||||
|
</div>
|
||||||
|
<div id="global-links">
|
||||||
|
<ul class="simple">
|
||||||
|
<li>
|
||||||
|
<a href="theindex.html">Index</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div id="searchInputDiv">
|
||||||
|
Search: <input type="text" id="searchInput"
|
||||||
|
onkeyup="search()" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
Group by:
|
||||||
|
<select onchange="groupBy(this.value)">
|
||||||
|
<option value="section">Section</option>
|
||||||
|
<option value="type">Type</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<ul class="simple simple-toc" id="toc-list">
|
||||||
|
<li><a class="reference" id="basic-usage_toc" href="#basic-usage">Basic Usage</a></li>
|
||||||
|
<ul class="simple"><li><a class="reference" id="basic-usage-example-db-schema_toc" href="#basic-usage-example-db-schema">Example DB Schema</a></li>
|
||||||
|
<li><a class="reference" id="basic-usage-example-model-definitions_toc" href="#basic-usage-example-model-definitions">Example Model Definitions</a></li>
|
||||||
|
<li><a class="reference" id="basic-usage-example-fiber-orm-usage_toc" href="#basic-usage-example-fiber-orm-usage">Example Fiber ORM Usage</a></li>
|
||||||
|
</ul><li><a class="reference" id="objectminusrelational-modeling_toc" href="#objectminusrelational-modeling">Object-Relational Modeling</a></li>
|
||||||
|
<ul class="simple"><li><a class="reference" id="objectminusrelational-modeling-model-class_toc" href="#objectminusrelational-modeling-model-class">Model Class</a></li>
|
||||||
|
<ul class="simple"><li><a class="reference" id="model-class-name-mapping_toc" href="#model-class-name-mapping">Name Mapping</a></li>
|
||||||
|
<li><a class="reference" id="model-class-id-field_toc" href="#model-class-id-field">ID Field</a></li>
|
||||||
|
</ul><li><a class="reference" id="objectminusrelational-modeling-supported-data-types_toc" href="#objectminusrelational-modeling-supported-data-types">Supported Data Types</a></li>
|
||||||
|
</ul><li><a class="reference" id="database-object_toc" href="#database-object">Database Object</a></li>
|
||||||
|
<li><a class="reference" id="see-also_toc" href="#see-also">See Also</a></li>
|
||||||
|
<li>
|
||||||
|
<a class="reference reference-toplevel" href="#6" id="56">Imports</a>
|
||||||
|
<ul class="simple simple-toc-section">
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a class="reference reference-toplevel" href="#7" id="57">Types</a>
|
||||||
|
<ul class="simple simple-toc-section">
|
||||||
|
<li><a class="reference" href="#NotFoundError"
|
||||||
|
title="NotFoundError = object of CatchableError">NotFoundError</a></li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a class="reference reference-toplevel" href="#12" id="62">Procs</a>
|
||||||
|
<ul class="simple simple-toc-section">
|
||||||
|
<ul class="simple nested-toc-section">createRecord
|
||||||
|
<li><a class="reference" href="#createRecord%2CDbConn%2CT"
|
||||||
|
title="createRecord[T](db: DbConn; rec: T): T">createRecord[T](db: DbConn; rec: T): T</a></li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
<ul class="simple nested-toc-section">deleteRecord
|
||||||
|
<li><a class="reference" href="#deleteRecord%2CDbConn%2CT"
|
||||||
|
title="deleteRecord[T](db: DbConn; rec: T): bool">deleteRecord[T](db: DbConn; rec: T): bool</a></li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
<ul class="simple nested-toc-section">initPool
|
||||||
|
<li><a class="reference" href="#initPool%2Cproc%29%2Cint%2Cstring"
|
||||||
|
title="initPool(connect: proc (): DbConn; poolSize = 10; hardCap = false;
|
||||||
|
healthCheckQuery = "SELECT \'true\' AS alive"): DbConnPool">initPool(connect: proc (): DbConn; poolSize = 10; hardCap = false;
|
||||||
|
healthCheckQuery = "SELECT \'true\' AS alive"): DbConnPool</a></li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
<ul class="simple nested-toc-section">updateRecord
|
||||||
|
<li><a class="reference" href="#updateRecord%2CDbConn%2CT"
|
||||||
|
title="updateRecord[T](db: DbConn; rec: T): bool">updateRecord[T](db: DbConn; rec: T): bool</a></li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a class="reference reference-toplevel" href="#17" id="67">Macros</a>
|
||||||
|
<ul class="simple simple-toc-section">
|
||||||
|
<ul class="simple nested-toc-section">generateLookup
|
||||||
|
<li><a class="reference" href="#generateLookup.m%2Ctype%2Ctype%2Cseq%5Bstring%5D"
|
||||||
|
title="generateLookup(dbType: type; modelType: type; fields: seq[string]): untyped">generateLookup(dbType: type; modelType: type; fields: seq[string]): untyped</a></li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
<ul class="simple nested-toc-section">generateProcsForFieldLookups
|
||||||
|
<li><a class="reference" href="#generateProcsForFieldLookups.m%2Ctype%2CopenArray%5Btuple%5Btype%2Cseq%5Bstring%5D%5D%5D"
|
||||||
|
title="generateProcsForFieldLookups(dbType: type; modelsAndFields: openArray[
|
||||||
|
tuple[t: type, fields: seq[string]]]): untyped">generateProcsForFieldLookups(dbType: type; modelsAndFields: openArray[
|
||||||
|
tuple[t: type, fields: seq[string]]]): untyped</a></li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
<ul class="simple nested-toc-section">generateProcsForModels
|
||||||
|
<li><a class="reference" href="#generateProcsForModels.m%2Ctype%2CopenArray%5Btype%5D"
|
||||||
|
title="generateProcsForModels(dbType: type; modelTypes: openArray[type]): untyped">generateProcsForModels(dbType: type; modelTypes: openArray[type]): untyped</a></li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a class="reference reference-toplevel" href="#18" id="68">Templates</a>
|
||||||
|
<ul class="simple simple-toc-section">
|
||||||
|
<ul class="simple nested-toc-section">deleteRecord
|
||||||
|
<li><a class="reference" href="#deleteRecord.t%2CDbConn%2Ctype%2Ctyped"
|
||||||
|
title="deleteRecord(db: DbConn; modelType: type; id: typed): untyped">deleteRecord(db: DbConn; modelType: type; id: typed): untyped</a></li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
<ul class="simple nested-toc-section">findRecordsBy
|
||||||
|
<li><a class="reference" href="#findRecordsBy.t%2CDbConn%2Ctype%2Cseq%5Btuple%5Bstring%2Cstring%5D%5D"
|
||||||
|
title="findRecordsBy(db: DbConn; modelType: type;
|
||||||
|
lookups: seq[tuple[field: string, value: string]]): untyped">findRecordsBy(db: DbConn; modelType: type;
|
||||||
|
lookups: seq[tuple[field: string, value: string]]): untyped</a></li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
<ul class="simple nested-toc-section">findRecordsWhere
|
||||||
|
<li><a class="reference" href="#findRecordsWhere.t%2CDbConn%2Ctype%2Cstring%2Cvarargs%5Bstring%2CdbFormat%5D"
|
||||||
|
title="findRecordsWhere(db: DbConn; modelType: type; whereClause: string;
|
||||||
|
values: varargs[string, dbFormat]): untyped">findRecordsWhere(db: DbConn; modelType: type; whereClause: string;
|
||||||
|
values: varargs[string, dbFormat]): untyped</a></li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
<ul class="simple nested-toc-section">getAllRecords
|
||||||
|
<li><a class="reference" href="#getAllRecords.t%2CDbConn%2Ctype"
|
||||||
|
title="getAllRecords(db: DbConn; modelType: type): untyped">getAllRecords(db: DbConn; modelType: type): untyped</a></li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
<ul class="simple nested-toc-section">getRecord
|
||||||
|
<li><a class="reference" href="#getRecord.t%2CDbConn%2Ctype%2Ctyped"
|
||||||
|
title="getRecord(db: DbConn; modelType: type; id: typed): untyped">getRecord(db: DbConn; modelType: type; id: typed): untyped</a></li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
<ul class="simple nested-toc-section">inTransaction
|
||||||
|
<li><a class="reference" href="#inTransaction.t%2CDbConnPool%2Cuntyped"
|
||||||
|
title="inTransaction(db: DbConnPool; body: untyped)">inTransaction(db: DbConnPool; body: untyped)</a></li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a class="reference reference-toplevel" href="#19" id="69">Exports</a>
|
||||||
|
<ul class="simple simple-toc-section">
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<a
|
||||||
|
href="https://github.com/jdbernard/fiber-orm/tree/version-1-6/src/fiber_orm.nim#L1"
|
||||||
|
class="link-seesrc" target="_blank">Source</a>
|
||||||
|
<a href="https://github.com/jdbernard/fiber-orm/edit/devel/src/fiber_orm.nim#L1" class="link-seesrc" target="_blank" >Edit</a>
|
||||||
|
|
||||||
|
<div class="nine columns" id="content">
|
||||||
|
<div id="tocRoot"></div>
|
||||||
|
|
||||||
|
<p class="module-desc"><p>Lightweight ORM supporting the <a class="reference external" href="https://nim-lang.org/docs/db_postgres.html">Postgres</a> and <a class="reference external" href="https://nim-lang.org/docs/db_sqlite.html">SQLite</a> databases in Nim. It supports a simple, opinionated model mapper to generate SQL queries based on Nim objects. It also includes a simple connection pooling implementation.</p>
|
||||||
|
<p>Fiber ORM is not intended to be a 100% all-cases-covered ORM that handles every potential data access pattern one might wish to implement. It is best thought of as a collection of common SQL generation patterns. It is intended to cover 90% of the common queries and functions one might write when implementing an SQL-based access layer. It is expected that there may be a few more complicated queries that need to be implemented to handle specific access patterns.</p>
|
||||||
|
<p>The simple mapping pattern provided by Fiber ORM also works well on top of databases that encapsulate data access logic in SQL with, for example, views.</p>
|
||||||
|
|
||||||
|
<h1><a class="toc-backref" id="basic-usage" href="#basic-usage">Basic Usage</a></h1><p>Consider a simple TODO list application that keeps track of TODO items as well as time logged against those items.</p>
|
||||||
|
|
||||||
|
<h2><a class="toc-backref" id="basic-usage-example-db-schema" href="#basic-usage-example-db-schema">Example DB Schema</a></h2><p>You might have a schema such as:</p>
|
||||||
|
<pre class="listing">create extension if not exists "pgcrypto";
|
||||||
|
|
||||||
|
create table todo_items columns (
|
||||||
|
id uuid not null primary key default gen_random_uuid(),
|
||||||
|
owner varchar not null,
|
||||||
|
summary varchar not null,
|
||||||
|
details varchar default null,
|
||||||
|
priority integer not null default 0,
|
||||||
|
related_todo_item_ids uuid[] not null default '{}'
|
||||||
|
);
|
||||||
|
|
||||||
|
create table time_entries columns (
|
||||||
|
id uuid not null primary key default gen_random_uuid(),
|
||||||
|
todo_item_id uuid not null references todo_items (id) on delete cascade,
|
||||||
|
start timestamp with timezone not null default current_timestamp,
|
||||||
|
stop timestamp with timezone default null,
|
||||||
|
);</pre>
|
||||||
|
<h2><a class="toc-backref" id="basic-usage-example-model-definitions" href="#basic-usage-example-model-definitions">Example Model Definitions</a></h2><p>Models may be defined as:</p>
|
||||||
|
<pre class="listing"><span class="Comment"># models.nim</span>
|
||||||
|
<span class="Keyword">import</span> <span class="Identifier">std</span><span class="Operator">/</span><span class="Identifier">options</span><span class="Punctuation">,</span> <span class="Identifier">std</span><span class="Operator">/</span><span class="Identifier">times</span>
|
||||||
|
<span class="Keyword">import</span> <span class="Identifier">uuids</span>
|
||||||
|
|
||||||
|
<span class="Keyword">type</span>
|
||||||
|
<span class="Identifier">TodoItem</span><span class="Operator">*</span> <span class="Operator">=</span> <span class="Keyword">object</span>
|
||||||
|
<span class="Identifier">id</span><span class="Operator">*:</span> <span class="Identifier">UUID</span>
|
||||||
|
<span class="Identifier">owner</span><span class="Operator">*:</span> <span class="Identifier">string</span>
|
||||||
|
<span class="Identifier">summary</span><span class="Operator">*:</span> <span class="Identifier">string</span>
|
||||||
|
<span class="Identifier">details</span><span class="Operator">*:</span> <span class="Identifier">Option</span><span class="Punctuation">[</span><span class="Identifier">string</span><span class="Punctuation">]</span>
|
||||||
|
<span class="Identifier">priority</span><span class="Operator">*:</span> <span class="Identifier">int</span>
|
||||||
|
<span class="Identifier">relatedTodoItemIds</span><span class="Operator">*:</span> <span class="Identifier">seq</span><span class="Punctuation">[</span><span class="Identifier">UUID</span><span class="Punctuation">]</span>
|
||||||
|
|
||||||
|
<span class="Identifier">TimeEntry</span><span class="Operator">*</span> <span class="Operator">=</span> <span class="Keyword">object</span>
|
||||||
|
<span class="Identifier">id</span><span class="Operator">*:</span> <span class="Identifier">UUID</span>
|
||||||
|
<span class="Identifier">todoItemId</span><span class="Operator">*:</span> <span class="Identifier">Option</span><span class="Punctuation">[</span><span class="Identifier">UUID</span><span class="Punctuation">]</span>
|
||||||
|
<span class="Identifier">start</span><span class="Operator">*:</span> <span class="Identifier">DateTime</span>
|
||||||
|
<span class="Identifier">stop</span><span class="Operator">*:</span> <span class="Identifier">Option</span><span class="Punctuation">[</span><span class="Identifier">DateTime</span><span class="Punctuation">]</span></pre>
|
||||||
|
<h2><a class="toc-backref" id="basic-usage-example-fiber-orm-usage" href="#basic-usage-example-fiber-orm-usage">Example Fiber ORM Usage</a></h2><p>Using Fiber ORM we can generate a data access layer with:</p>
|
||||||
|
<pre class="listing"><span class="Comment"># db.nim</span>
|
||||||
|
<span class="Keyword">import</span> <span class="Identifier">fiber_orm</span>
|
||||||
|
<span class="Keyword">import</span> <span class="Operator">./</span><span class="Identifier">models</span><span class="Operator">.</span><span class="Identifier">nim</span>
|
||||||
|
|
||||||
|
<span class="Keyword">type</span> <span class="Identifier">TodoDB</span><span class="Operator">*</span> <span class="Operator">=</span> <span class="Identifier">DbConnPool</span>
|
||||||
|
|
||||||
|
<span class="Keyword">proc</span> <span class="Identifier">initDb</span><span class="Operator">*</span><span class="Punctuation">(</span><span class="Identifier">connString</span><span class="Punctuation">:</span> <span class="Identifier">string</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">TodoDB</span> <span class="Operator">=</span>
|
||||||
|
<span class="Identifier">result</span> <span class="Operator">=</span> <span class="Identifier">fiber_orm</span><span class="Operator">.</span><span class="Identifier">initPool</span><span class="Punctuation">(</span>
|
||||||
|
<span class="Identifier">connect</span> <span class="Operator">=</span> <span class="Keyword">proc</span><span class="Punctuation">(</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">DbConn</span> <span class="Operator">=</span> <span class="Identifier">open</span><span class="Punctuation">(</span><span class="StringLit">""</span><span class="Punctuation">,</span> <span class="StringLit">""</span><span class="Punctuation">,</span> <span class="StringLit">""</span><span class="Punctuation">,</span> <span class="Identifier">connString</span><span class="Punctuation">)</span><span class="Punctuation">,</span>
|
||||||
|
<span class="Identifier">poolSize</span> <span class="Operator">=</span> <span class="DecNumber">20</span><span class="Punctuation">,</span>
|
||||||
|
<span class="Identifier">hardCap</span> <span class="Operator">=</span> <span class="Identifier">false</span><span class="Punctuation">)</span>
|
||||||
|
|
||||||
|
|
||||||
|
<span class="Identifier">generateProcsForModels</span><span class="Punctuation">(</span><span class="Identifier">TodoDB</span><span class="Punctuation">,</span> <span class="Punctuation">[</span><span class="Identifier">TodoItem</span><span class="Punctuation">,</span> <span class="Identifier">TimeEntry</span><span class="Punctuation">]</span><span class="Punctuation">)</span>
|
||||||
|
|
||||||
|
<span class="Identifier">generateLookup</span><span class="Punctuation">(</span><span class="Identifier">TodoDB</span><span class="Punctuation">,</span> <span class="Identifier">TimeEntry</span><span class="Punctuation">,</span> <span class="Operator">@</span><span class="Punctuation">[</span><span class="StringLit">"todoItemId"</span><span class="Punctuation">]</span><span class="Punctuation">)</span></pre><p>This will generate the following procedures:</p>
|
||||||
|
<pre class="listing"><span class="Keyword">proc</span> <span class="Identifier">getTodoItem</span><span class="Operator">*</span><span class="Punctuation">(</span><span class="Identifier">db</span><span class="Punctuation">:</span> <span class="Identifier">TodoDB</span><span class="Punctuation">,</span> <span class="Identifier">id</span><span class="Punctuation">:</span> <span class="Identifier">UUID</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">TodoItem</span><span class="Punctuation">;</span>
|
||||||
|
<span class="Keyword">proc</span> <span class="Identifier">getAllTodoItems</span><span class="Operator">*</span><span class="Punctuation">(</span><span class="Identifier">db</span><span class="Punctuation">:</span> <span class="Identifier">TodoDB</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">seq</span><span class="Punctuation">[</span><span class="Identifier">TodoItem</span><span class="Punctuation">]</span><span class="Punctuation">;</span>
|
||||||
|
<span class="Keyword">proc</span> <span class="Identifier">createTodoItem</span><span class="Operator">*</span><span class="Punctuation">(</span><span class="Identifier">db</span><span class="Punctuation">:</span> <span class="Identifier">TodoDB</span><span class="Punctuation">,</span> <span class="Identifier">rec</span><span class="Punctuation">:</span> <span class="Identifier">TodoItem</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">TodoItem</span><span class="Punctuation">;</span>
|
||||||
|
<span class="Keyword">proc</span> <span class="Identifier">updateTodoItem</span><span class="Operator">*</span><span class="Punctuation">(</span><span class="Identifier">db</span><span class="Punctuation">:</span> <span class="Identifier">TodoDB</span><span class="Punctuation">,</span> <span class="Identifier">rec</span><span class="Punctuation">:</span> <span class="Identifier">TodoItem</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">bool</span><span class="Punctuation">;</span>
|
||||||
|
<span class="Keyword">proc</span> <span class="Identifier">deleteTodoItem</span><span class="Operator">*</span><span class="Punctuation">(</span><span class="Identifier">db</span><span class="Punctuation">:</span> <span class="Identifier">TodoDB</span><span class="Punctuation">,</span> <span class="Identifier">rec</span><span class="Punctuation">:</span> <span class="Identifier">TodoItem</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">bool</span><span class="Punctuation">;</span>
|
||||||
|
<span class="Keyword">proc</span> <span class="Identifier">deleteTodoItem</span><span class="Operator">*</span><span class="Punctuation">(</span><span class="Identifier">db</span><span class="Punctuation">:</span> <span class="Identifier">TodoDB</span><span class="Punctuation">,</span> <span class="Identifier">id</span><span class="Punctuation">:</span> <span class="Identifier">UUID</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">bool</span><span class="Punctuation">;</span>
|
||||||
|
|
||||||
|
<span class="Keyword">proc</span> <span class="Identifier">findTodoItemsWhere</span><span class="Operator">*</span><span class="Punctuation">(</span><span class="Identifier">db</span><span class="Punctuation">:</span> <span class="Identifier">TodoDB</span><span class="Punctuation">,</span> <span class="Identifier">whereClause</span><span class="Punctuation">:</span> <span class="Identifier">string</span><span class="Punctuation">,</span>
|
||||||
|
<span class="Identifier">values</span><span class="Punctuation">:</span> <span class="Identifier">varargs</span><span class="Punctuation">[</span><span class="Identifier">string</span><span class="Punctuation">,</span> <span class="Identifier">dbFormat</span><span class="Punctuation">]</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">seq</span><span class="Punctuation">[</span><span class="Identifier">TodoItem</span><span class="Punctuation">]</span><span class="Punctuation">;</span>
|
||||||
|
|
||||||
|
<span class="Keyword">proc</span> <span class="Identifier">getTimeEntry</span><span class="Operator">*</span><span class="Punctuation">(</span><span class="Identifier">db</span><span class="Punctuation">:</span> <span class="Identifier">TodoDB</span><span class="Punctuation">,</span> <span class="Identifier">id</span><span class="Punctuation">:</span> <span class="Identifier">UUID</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">TimeEntry</span><span class="Punctuation">;</span>
|
||||||
|
<span class="Keyword">proc</span> <span class="Identifier">getAllTimeEntries</span><span class="Operator">*</span><span class="Punctuation">(</span><span class="Identifier">db</span><span class="Punctuation">:</span> <span class="Identifier">TodoDB</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">seq</span><span class="Punctuation">[</span><span class="Identifier">TimeEntry</span><span class="Punctuation">]</span><span class="Punctuation">;</span>
|
||||||
|
<span class="Keyword">proc</span> <span class="Identifier">createTimeEntry</span><span class="Operator">*</span><span class="Punctuation">(</span><span class="Identifier">db</span><span class="Punctuation">:</span> <span class="Identifier">TodoDB</span><span class="Punctuation">,</span> <span class="Identifier">rec</span><span class="Punctuation">:</span> <span class="Identifier">TimeEntry</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">TimeEntry</span><span class="Punctuation">;</span>
|
||||||
|
<span class="Keyword">proc</span> <span class="Identifier">updateTimeEntry</span><span class="Operator">*</span><span class="Punctuation">(</span><span class="Identifier">db</span><span class="Punctuation">:</span> <span class="Identifier">TodoDB</span><span class="Punctuation">,</span> <span class="Identifier">rec</span><span class="Punctuation">:</span> <span class="Identifier">TimeEntry</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">bool</span><span class="Punctuation">;</span>
|
||||||
|
<span class="Keyword">proc</span> <span class="Identifier">deleteTimeEntry</span><span class="Operator">*</span><span class="Punctuation">(</span><span class="Identifier">db</span><span class="Punctuation">:</span> <span class="Identifier">TodoDB</span><span class="Punctuation">,</span> <span class="Identifier">rec</span><span class="Punctuation">:</span> <span class="Identifier">TimeEntry</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">bool</span><span class="Punctuation">;</span>
|
||||||
|
<span class="Keyword">proc</span> <span class="Identifier">deleteTimeEntry</span><span class="Operator">*</span><span class="Punctuation">(</span><span class="Identifier">db</span><span class="Punctuation">:</span> <span class="Identifier">TodoDB</span><span class="Punctuation">,</span> <span class="Identifier">id</span><span class="Punctuation">:</span> <span class="Identifier">UUID</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">bool</span><span class="Punctuation">;</span>
|
||||||
|
|
||||||
|
<span class="Keyword">proc</span> <span class="Identifier">findTimeEntriesWhere</span><span class="Operator">*</span><span class="Punctuation">(</span><span class="Identifier">db</span><span class="Punctuation">:</span> <span class="Identifier">TodoDB</span><span class="Punctuation">,</span> <span class="Identifier">whereClause</span><span class="Punctuation">:</span> <span class="Identifier">string</span><span class="Punctuation">,</span>
|
||||||
|
<span class="Identifier">values</span><span class="Punctuation">:</span> <span class="Identifier">varargs</span><span class="Punctuation">[</span><span class="Identifier">string</span><span class="Punctuation">,</span> <span class="Identifier">dbFormat</span><span class="Punctuation">]</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">seq</span><span class="Punctuation">[</span><span class="Identifier">TimeEntry</span><span class="Punctuation">]</span><span class="Punctuation">;</span>
|
||||||
|
|
||||||
|
<span class="Keyword">proc</span> <span class="Identifier">findTimeEntriesByTodoItemId</span><span class="Punctuation">(</span><span class="Identifier">db</span><span class="Punctuation">:</span> <span class="Identifier">TodoDB</span><span class="Punctuation">,</span> <span class="Identifier">todoItemId</span><span class="Punctuation">:</span> <span class="Identifier">UUID</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">seq</span><span class="Punctuation">[</span><span class="Identifier">TimeEntry</span><span class="Punctuation">]</span><span class="Punctuation">;</span></pre>
|
||||||
|
<h1><a class="toc-backref" id="objectminusrelational-modeling" href="#objectminusrelational-modeling">Object-Relational Modeling</a></h1>
|
||||||
|
<h2><a class="toc-backref" id="objectminusrelational-modeling-model-class" href="#objectminusrelational-modeling-model-class">Model Class</a></h2><p>Fiber ORM uses simple Nim <tt class="docutils literal"><span class="pre"><span class="Keyword">object</span></span></tt>s and <tt class="docutils literal"><span class="pre"><span class="Keyword">ref</span> <span class="Keyword">object</span></span></tt>s as model classes. Fiber ORM expects there to be one table for each model class.</p>
|
||||||
|
|
||||||
|
<h3><a class="toc-backref" id="model-class-name-mapping" href="#model-class-name-mapping">Name Mapping</a></h3><p>Fiber ORM uses <tt class="docutils literal"><span class="pre"><span class="Identifier">snake_case</span></span></tt> for database identifiers (column names, table names, etc.) and <tt class="docutils literal"><span class="pre"><span class="Identifier">camelCase</span></span></tt> for Nim identifiers. We automatically convert model names to and from table names (<tt class="docutils literal"><span class="pre"><span class="Identifier">TodoItem</span></span></tt> <-> <tt class="docutils literal"><span class="pre"><span class="Identifier">todo_items</span></span></tt>), as well as column names (<tt class="docutils literal"><span class="pre"><span class="Identifier">userId</span></span></tt> <-> <tt class="docutils literal"><span class="pre"><span class="Identifier">user_id</span></span></tt>).</p>
|
||||||
|
<p>Notice that table names are automatically pluralized from model class names. In the above example, you have:</p>
|
||||||
|
<table border="1" class="docutils"><tr><th>Model Class</th><th>Table Name</th></tr>
|
||||||
|
<tr><td>TodoItem</td><td>todo_items</td></tr>
|
||||||
|
<tr><td>TimeEntry</td><td>time_entries</td></tr>
|
||||||
|
</table><p>Because Nim is style-insensitive, you can generall refer to model classes and fields using <tt class="docutils literal"><span class="pre"><span class="Identifier">snake_case</span></span></tt>, <tt class="docutils literal"><span class="pre"><span class="Identifier">camelCase</span></span></tt>, or <tt class="docutils literal"><span class="pre"><span class="Identifier">PascalCase</span></span></tt> in your code and expect Fiber ORM to be able to map the names to DB identifier names properly (though FiberORM will always use <tt class="docutils literal"><span class="pre"><span class="Identifier">camelCase</span></span></tt> internally).</p>
|
||||||
|
<p>See the <a class="reference external" href="fiber_orm/util.html#identNameToDb,string">identNameToDb</a>, <a class="reference external" href="fiber_orm/util.html#dbNameToIdent,string">dbNameToIdent</a>, <a class="reference external" href="fiber_orm/util.html#tableName,type">tableName</a> and <a class="reference external" href="fiber_orm/util.html#dbFormat,DateTime">dbFormat</a> procedures in the <a class="reference internal" href="#fiber">fiber</a> module for details.</p>
|
||||||
|
|
||||||
|
<h3><a class="toc-backref" id="model-class-id-field" href="#model-class-id-field">ID Field</a></h3><p>Fiber ORM expects every model class to have a field named <tt class="docutils literal"><span class="pre"><span class="Identifier">id</span></span></tt>, with a corresponding <tt class="docutils literal"><span class="pre"><span class="Identifier">id</span></span></tt> column in the model table. This field must be either a <tt class="docutils literal"><span class="pre"><span class="Identifier">string</span></span></tt>, <tt class="docutils literal"><span class="pre"><span class="Identifier">integer</span></span></tt>, or <a class="reference external" href="https://github.com/pragmagic/uuids">UUID</a>.</p>
|
||||||
|
<p>When creating a new record the <tt class="docutils literal"><span class="pre"><span class="Identifier">id</span></span></tt> field will be omitted if it is empty (<a class="reference external" href="https://nim-lang.org/docs/options.html#isNone,Option[T]">Option.isNone</a>, <a class="reference external" href="https://github.com/pragmagic/uuids/blob/8cb8720b567c6bcb261bd1c0f7491bdb5209ad06/uuids.nim#L72">UUID.isZero</a>, value of <tt class="docutils literal"><span class="pre"><span class="DecNumber">0</span></span></tt>, or only whitespace). This is intended to allow for cases like the example where the database may generate an ID when a new record is inserted. If a non-zero value is provided, the create call will include the <tt class="docutils literal"><span class="pre"><span class="Identifier">id</span></span></tt> field in the <tt class="docutils literal"><span class="pre"><span class="Identifier">INSERT</span></span></tt> query.</p>
|
||||||
|
<p>For example, to allow the database to create the id:</p>
|
||||||
|
<pre class="listing"><span class="Keyword">let</span> <span class="Identifier">item</span> <span class="Operator">=</span> <span class="Identifier">TodoItem</span><span class="Punctuation">(</span>
|
||||||
|
<span class="Identifier">owner</span><span class="Punctuation">:</span> <span class="StringLit">"John Mann"</span><span class="Punctuation">,</span>
|
||||||
|
<span class="Identifier">summary</span><span class="Punctuation">:</span> <span class="StringLit">"Create a grocery list."</span><span class="Punctuation">,</span>
|
||||||
|
<span class="Identifier">details</span><span class="Punctuation">:</span> <span class="Identifier">none</span><span class="Punctuation">[</span><span class="Identifier">string</span><span class="Punctuation">]</span><span class="Punctuation">(</span><span class="Punctuation">)</span><span class="Punctuation">,</span>
|
||||||
|
<span class="Identifier">priority</span><span class="Punctuation">:</span> <span class="DecNumber">0</span><span class="Punctuation">,</span>
|
||||||
|
<span class="Identifier">relatedTodoItemIds</span><span class="Punctuation">:</span> <span class="Operator">@</span><span class="Punctuation">[</span><span class="Punctuation">]</span><span class="Punctuation">)</span>
|
||||||
|
|
||||||
|
<span class="Keyword">let</span> <span class="Identifier">itemWithId</span> <span class="Operator">=</span> <span class="Identifier">db</span><span class="Operator">.</span><span class="Identifier">createTodoItem</span><span class="Punctuation">(</span><span class="Identifier">item</span><span class="Punctuation">)</span>
|
||||||
|
<span class="Identifier">echo</span> <span class="Operator">$</span><span class="Identifier">itemWithId</span><span class="Operator">.</span><span class="Identifier">id</span> <span class="Comment"># generated in the database</span></pre><p>And to create it in code:</p>
|
||||||
|
<pre class="listing"><span class="Keyword">import</span> <span class="Identifier">uuids</span>
|
||||||
|
|
||||||
|
<span class="Keyword">let</span> <span class="Identifier">item</span> <span class="Operator">=</span> <span class="Identifier">TodoItem</span><span class="Punctuation">(</span>
|
||||||
|
<span class="Identifier">id</span><span class="Punctuation">:</span> <span class="Identifier">genUUID</span><span class="Punctuation">(</span><span class="Punctuation">)</span><span class="Punctuation">,</span>
|
||||||
|
<span class="Identifier">owner</span><span class="Punctuation">:</span> <span class="StringLit">"John Mann"</span><span class="Punctuation">,</span>
|
||||||
|
<span class="Identifier">summary</span><span class="Punctuation">:</span> <span class="StringLit">"Create a grocery list."</span><span class="Punctuation">,</span>
|
||||||
|
<span class="Identifier">details</span><span class="Punctuation">:</span> <span class="Identifier">none</span><span class="Punctuation">[</span><span class="Identifier">string</span><span class="Punctuation">]</span><span class="Punctuation">(</span><span class="Punctuation">)</span><span class="Punctuation">,</span>
|
||||||
|
<span class="Identifier">priority</span><span class="Punctuation">:</span> <span class="DecNumber">0</span><span class="Punctuation">,</span>
|
||||||
|
<span class="Identifier">relatedTodoItemIds</span><span class="Punctuation">:</span> <span class="Operator">@</span><span class="Punctuation">[</span><span class="Punctuation">]</span><span class="Punctuation">)</span>
|
||||||
|
|
||||||
|
<span class="Keyword">let</span> <span class="Identifier">itemInDb</span> <span class="Operator">=</span> <span class="Identifier">db</span><span class="Operator">.</span><span class="Identifier">createTodoItem</span><span class="Punctuation">(</span><span class="Identifier">item</span><span class="Punctuation">)</span>
|
||||||
|
<span class="Identifier">echo</span> <span class="Operator">$</span><span class="Identifier">itemInDb</span><span class="Operator">.</span><span class="Identifier">id</span> <span class="Comment"># will be the same as what was provided</span></pre>
|
||||||
|
<h2><a class="toc-backref" id="objectminusrelational-modeling-supported-data-types" href="#objectminusrelational-modeling-supported-data-types">Supported Data Types</a></h2><p>The following Nim data types are supported by Fiber ORM:</p>
|
||||||
|
<table border="1" class="docutils"><tr><th>Nim Type</th><th>Postgres Type</th><th>SQLite Type</th></tr>
|
||||||
|
<tr><td><tt class="docutils literal"><span class="pre"><span class="Identifier">string</span></span></tt></td><td><a class="reference external" href="https://www.postgresql.org/docs/current/datatype-character.html">varchar</a></td><td></td></tr>
|
||||||
|
<tr><td><tt class="docutils literal"><span class="pre"><span class="Identifier">int</span></span></tt></td><td><a class="reference external" href="https://www.postgresql.org/docs/current/datatype-numeric.html#DATATYPE-INT">integer</a></td><td></td></tr>
|
||||||
|
<tr><td><tt class="docutils literal"><span class="pre"><span class="Identifier">float</span></span></tt></td><td><a class="reference external" href="https://www.postgresql.org/docs/current/datatype-numeric.html#DATATYPE-FLOAT">double</a></td><td></td></tr>
|
||||||
|
<tr><td><tt class="docutils literal"><span class="pre"><span class="Identifier">bool</span></span></tt></td><td><a class="reference external" href="https://www.postgresql.org/docs/current/datatype-boolean.html">boolean</a></td><td></td></tr>
|
||||||
|
<tr><td><a class="reference external" href="https://nim-lang.org/docs/times.html#DateTime">DateTime</a></td><td><a class="reference external" href="https://www.postgresql.org/docs/current/datatype-datetime.html">timestamp</a></td><td></td></tr>
|
||||||
|
<tr><td><tt class="docutils literal"><span class="pre"><span class="Identifier">seq</span><span class="Punctuation">[</span><span class="Punctuation">]</span></span></tt></td><td><a class="reference external" href="https://www.postgresql.org/docs/current/arrays.html">array</a></td><td></td></tr>
|
||||||
|
<tr><td><a class="reference external" href="https://github.com/pragmagic/uuids">UUID</a></td><td><a class="reference external" href="https://www.postgresql.org/docs/current/datatype-uuid.html">uuid (pg)</a></td><td></td></tr>
|
||||||
|
<tr><td><a class="reference external" href="https://nim-lang.org/docs/options.html#Option">Option</a></td><td><em>allows</em> <tt class="docutils literal"><span class="pre"><span class="Identifier">NULL</span></span></tt> <sup><strong><a class="reference internal" href="#footnote-f1">[1]</a></strong></sup></td><td></td></tr>
|
||||||
|
<tr><td><a class="reference external" href="https://nim-lang.org/docs/json.html#JsonNode">JsonNode</a></td><td><a class="reference external" href="https://www.postgresql.org/docs/current/datatype-json.html">jsonb</a></td><td></td></tr>
|
||||||
|
</table><hr class="footnote"><div class="footnote-group">
|
||||||
|
<div id="footnote-f1"><div class="footnote-label"><sup><strong><a href="#footnote-f1">[1]</a></strong></sup></div>   Note that this implies that all <tt class="docutils literal"><span class="pre"><span class="Identifier">NULL</span></span></tt>-able fields should be typed as optional using <tt class="docutils literal"><span class="pre"><span class="Identifier">Option</span><span class="Punctuation">[</span><span class="Identifier">fieldType</span><span class="Punctuation">]</span></span></tt>. Conversely, any fields with non-optional types should also be constrained to be <tt class="docutils literal"><span class="pre"><span class="Keyword">NOT</span> <span class="Identifier">NULL</span></span></tt> in the database schema.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h1><a class="toc-backref" id="database-object" href="#database-object">Database Object</a></h1><p>Many of the Fiber ORM macros expect a database object type to be passed. In the example above the <a class="reference external" href="fiber_orm/pool.html#DbConnPool">pool.DbConnPool</a> object is used as database object type (aliased as <tt class="docutils literal"><span class="pre"><span class="Identifier">TodoDB</span></span></tt>). This is the intended usage pattern, but anything can be passed as the database object type so long as there is a defined <tt class="docutils literal"><span class="pre"><span class="Identifier">withConn</span></span></tt> template that provides an injected <tt class="docutils literal"><span class="pre"><span class="Identifier">conn</span><span class="Punctuation">:</span> <span class="Identifier">DbConn</span></span></tt> object to the provided statement body.</p>
|
||||||
|
<p>For example, a valid database object implementation that opens a new connection for every request might look like this:</p>
|
||||||
|
<pre class="listing"><span class="Keyword">import</span> <span class="Identifier">std</span><span class="Operator">/</span><span class="Identifier">db_postgres</span>
|
||||||
|
|
||||||
|
<span class="Keyword">type</span> <span class="Identifier">TodoDB</span><span class="Operator">*</span> <span class="Operator">=</span> <span class="Keyword">object</span>
|
||||||
|
<span class="Identifier">connString</span><span class="Punctuation">:</span> <span class="Identifier">string</span>
|
||||||
|
|
||||||
|
<span class="Keyword">template</span> <span class="Identifier">withConn</span><span class="Operator">*</span><span class="Punctuation">(</span><span class="Identifier">db</span><span class="Punctuation">:</span> <span class="Identifier">TodoDB</span><span class="Punctuation">,</span> <span class="Identifier">stmt</span><span class="Punctuation">:</span> <span class="Identifier">untyped</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">untyped</span> <span class="Operator">=</span>
|
||||||
|
<span class="Keyword">let</span> <span class="Identifier">conn</span> <span class="Punctuation">{</span><span class="Operator">.</span><span class="Identifier">inject</span><span class="Operator">.</span><span class="Punctuation">}</span> <span class="Operator">=</span> <span class="Identifier">open</span><span class="Punctuation">(</span><span class="StringLit">""</span><span class="Punctuation">,</span> <span class="StringLit">""</span><span class="Punctuation">,</span> <span class="StringLit">""</span><span class="Punctuation">,</span> <span class="Identifier">db</span><span class="Operator">.</span><span class="Identifier">connString</span><span class="Punctuation">)</span>
|
||||||
|
<span class="Keyword">try</span><span class="Punctuation">:</span> <span class="Identifier">stmt</span>
|
||||||
|
<span class="Keyword">finally</span><span class="Punctuation">:</span> <span class="Identifier">close</span><span class="Punctuation">(</span><span class="Identifier">conn</span><span class="Punctuation">)</span></pre>
|
||||||
|
<h1><a class="toc-backref" id="see-also" href="#see-also">See Also</a></h1><p><a class="reference external" href="fiber_orm/pool.html">fiber_orm/pool</a></p>
|
||||||
|
</p>
|
||||||
|
<div class="section" id="6">
|
||||||
|
<h1><a class="toc-backref" href="#6">Imports</a></h1>
|
||||||
|
<dl class="item">
|
||||||
|
<a class="reference external" href="fiber_orm/pool.html">fiber_orm/pool</a>, <a class="reference external" href="fiber_orm/util.html">fiber_orm/util</a>
|
||||||
|
</dl></div>
|
||||||
|
<div class="section" id="7">
|
||||||
|
<h1><a class="toc-backref" href="#7">Types</a></h1>
|
||||||
|
<dl class="item">
|
||||||
|
<div id="NotFoundError">
|
||||||
|
<dt><pre><a href="fiber_orm.html#NotFoundError"><span class="Identifier">NotFoundError</span></a> <span class="Other">=</span> <span class="Keyword">object</span> <span class="Keyword">of</span> <span class="Identifier">CatchableError</span></pre></dt>
|
||||||
|
<dd>
|
||||||
|
|
||||||
|
|
||||||
|
Error type raised when no record matches a given ID
|
||||||
|
<a
|
||||||
|
href="https://github.com/jdbernard/fiber-orm/tree/version-1-6/src/fiber_orm.nim#L299"
|
||||||
|
class="link-seesrc" target="_blank">Source</a>
|
||||||
|
<a href="https://github.com/jdbernard/fiber-orm/edit/devel/src/fiber_orm.nim#L299" class="link-seesrc" target="_blank" >Edit</a>
|
||||||
|
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</dl></div>
|
||||||
|
<div class="section" id="12">
|
||||||
|
<h1><a class="toc-backref" href="#12">Procs</a></h1>
|
||||||
|
<dl class="item">
|
||||||
|
<div id="createRecord,DbConn,T">
|
||||||
|
<dt><pre><span class="Keyword">proc</span> <a href="#createRecord%2CDbConn%2CT"><span class="Identifier">createRecord</span></a><span class="Other">[</span><span class="Identifier">T</span><span class="Other">]</span><span class="Other">(</span><span class="Identifier">db</span><span class="Other">:</span> <span class="Identifier">DbConn</span><span class="Other">;</span> <span class="Identifier">rec</span><span class="Other">:</span> <span class="Identifier">T</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">T</span></pre></dt>
|
||||||
|
<dd>
|
||||||
|
|
||||||
|
<p>Create a new record. <tt class="docutils literal"><span class="pre"><span class="Identifier">rec</span></span></tt> is expected to be a <a class="reference external" href="#objectminusrelational-modeling-model-class">model class</a>. The <tt class="docutils literal"><span class="pre"><span class="Identifier">id</span></span></tt> field is only set if it is non-empty (see <a class="reference external" href="#model-class-id-field">ID Field</a> for details).</p>
|
||||||
|
<p>Returns the newly created record.</p>
|
||||||
|
|
||||||
|
<a
|
||||||
|
href="https://github.com/jdbernard/fiber-orm/tree/version-1-6/src/fiber_orm.nim#L314"
|
||||||
|
class="link-seesrc" target="_blank">Source</a>
|
||||||
|
<a href="https://github.com/jdbernard/fiber-orm/edit/devel/src/fiber_orm.nim#L314" class="link-seesrc" target="_blank" >Edit</a>
|
||||||
|
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
<div id="deleteRecord,DbConn,T">
|
||||||
|
<dt><pre><span class="Keyword">proc</span> <a href="#deleteRecord%2CDbConn%2CT"><span class="Identifier">deleteRecord</span></a><span class="Other">[</span><span class="Identifier">T</span><span class="Other">]</span><span class="Other">(</span><span class="Identifier">db</span><span class="Other">:</span> <span class="Identifier">DbConn</span><span class="Other">;</span> <span class="Identifier">rec</span><span class="Other">:</span> <span class="Identifier">T</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">bool</span></pre></dt>
|
||||||
|
<dd>
|
||||||
|
|
||||||
|
Delete a record by <a class="reference external" href="#model-class-id-field">id</a>.
|
||||||
|
<a
|
||||||
|
href="https://github.com/jdbernard/fiber-orm/tree/version-1-6/src/fiber_orm.nim#L359"
|
||||||
|
class="link-seesrc" target="_blank">Source</a>
|
||||||
|
<a href="https://github.com/jdbernard/fiber-orm/edit/devel/src/fiber_orm.nim#L359" class="link-seesrc" target="_blank" >Edit</a>
|
||||||
|
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
<div id="initPool,proc),int,string">
|
||||||
|
<dt><pre><span class="Keyword">proc</span> <a href="#initPool%2Cproc%29%2Cint%2Cstring"><span class="Identifier">initPool</span></a><span class="Other">(</span><span class="Identifier">connect</span><span class="Other">:</span> <span class="Keyword">proc</span> <span class="Other">(</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">DbConn</span><span class="Other">;</span> <span class="Identifier">poolSize</span> <span class="Other">=</span> <span class="DecNumber">10</span><span class="Other">;</span> <span class="Identifier">hardCap</span> <span class="Other">=</span> <span class="Identifier">false</span><span class="Other">;</span>
|
||||||
|
<span class="Identifier">healthCheckQuery</span> <span class="Other">=</span> <span class="StringLit">"SELECT \'true\' AS alive"</span><span class="Other">)</span><span class="Other">:</span> <a href="fiber_orm/pool.html#DbConnPool"><span class="Identifier">DbConnPool</span></a> {.
|
||||||
|
<span><span class="Other pragmadots">...</span></span><span class="pragmawrap"><span class="Identifier">raises</span><span class="Other">:</span> <span class="Other">[</span><span class="Identifier">Exception</span><span class="Other">]</span><span class="Other">,</span> <span class="Identifier">tags</span><span class="Other">:</span> <span class="Other">[</span><span class="Identifier">RootEffect</span><span class="Other">]</span></span>.}</pre></dt>
|
||||||
|
<dd>
|
||||||
|
|
||||||
|
Initialize a new DbConnPool. See the <tt class="docutils literal"><span class="pre"><span class="Identifier">initDb</span></span></tt> procedure in the <a class="reference external" href="#basic-usage-example-fiber-orm-usage">Example Fiber ORM Usage</a> for an example<ul class="simple"><li><tt class="docutils literal"><span class="pre"><span class="Identifier">connect</span></span></tt> must be a factory which creates a new <tt class="docutils literal"><span class="pre"><span class="Identifier">DbConn</span></span></tt>.</li>
|
||||||
|
<li><tt class="docutils literal"><span class="pre"><span class="Identifier">poolSize</span></span></tt> sets the desired capacity of the connection pool.</li>
|
||||||
|
<li><p><tt class="docutils literal"><span class="pre"><span class="Identifier">hardCap</span></span></tt> defaults to <tt class="docutils literal"><span class="pre"><span class="Identifier">false</span></span></tt>. When <tt class="docutils literal"><span class="pre"><span class="Identifier">false</span></span></tt>, the pool can grow beyond the configured capacity, but will release connections down to the its capacity (no less than <tt class="docutils literal"><span class="pre"><span class="Identifier">poolSize</span></span></tt>).</p>
|
||||||
|
<p>When <tt class="docutils literal"><span class="pre"><span class="Identifier">true</span></span></tt> the pool will not create more than its configured capacity. It a connection is requested, none are free, and the pool is at capacity, this will result in an Error being raised.</p>
|
||||||
|
</li>
|
||||||
|
<li><tt class="docutils literal"><span class="pre"><span class="Identifier">healthCheckQuery</span></span></tt> should be a simple and fast SQL query that the pool can use to test the liveliness of pooled connections.</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<a
|
||||||
|
href="https://github.com/jdbernard/fiber-orm/tree/version-1-6/src/fiber_orm.nim#L539"
|
||||||
|
class="link-seesrc" target="_blank">Source</a>
|
||||||
|
<a href="https://github.com/jdbernard/fiber-orm/edit/devel/src/fiber_orm.nim#L539" class="link-seesrc" target="_blank" >Edit</a>
|
||||||
|
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
<div id="updateRecord,DbConn,T">
|
||||||
|
<dt><pre><span class="Keyword">proc</span> <a href="#updateRecord%2CDbConn%2CT"><span class="Identifier">updateRecord</span></a><span class="Other">[</span><span class="Identifier">T</span><span class="Other">]</span><span class="Other">(</span><span class="Identifier">db</span><span class="Other">:</span> <span class="Identifier">DbConn</span><span class="Other">;</span> <span class="Identifier">rec</span><span class="Other">:</span> <span class="Identifier">T</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">bool</span></pre></dt>
|
||||||
|
<dd>
|
||||||
|
|
||||||
|
Update a record by id. <tt class="docutils literal"><span class="pre"><span class="Identifier">rec</span></span></tt> is expected to be a <a class="reference external" href="#objectminusrelational-modeling-model-class">model class</a>.
|
||||||
|
<a
|
||||||
|
href="https://github.com/jdbernard/fiber-orm/tree/version-1-6/src/fiber_orm.nim#L337"
|
||||||
|
class="link-seesrc" target="_blank">Source</a>
|
||||||
|
<a href="https://github.com/jdbernard/fiber-orm/edit/devel/src/fiber_orm.nim#L337" class="link-seesrc" target="_blank" >Edit</a>
|
||||||
|
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</dl></div>
|
||||||
|
<div class="section" id="17">
|
||||||
|
<h1><a class="toc-backref" href="#17">Macros</a></h1>
|
||||||
|
<dl class="item">
|
||||||
|
<div id="generateLookup.m,type,type,seq[string]">
|
||||||
|
<dt><pre><span class="Keyword">macro</span> <a href="#generateLookup.m%2Ctype%2Ctype%2Cseq%5Bstring%5D"><span class="Identifier">generateLookup</span></a><span class="Other">(</span><span class="Identifier">dbType</span><span class="Other">:</span> <span class="Identifier">type</span><span class="Other">;</span> <span class="Identifier">modelType</span><span class="Other">:</span> <span class="Identifier">type</span><span class="Other">;</span> <span class="Identifier">fields</span><span class="Other">:</span> <span class="Identifier">seq</span><span class="Other">[</span><span class="Identifier">string</span><span class="Other">]</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">untyped</span></pre></dt>
|
||||||
|
<dd>
|
||||||
|
|
||||||
|
Create a lookup procedure for a given set of field names. For example, given the TODO database demostrated above,<pre class="listing"><span class="Identifier">generateLookup</span><span class="Punctuation">(</span><span class="Identifier">TodoDB</span><span class="Punctuation">,</span> <span class="Identifier">TodoItem</span><span class="Punctuation">,</span> <span class="Punctuation">[</span><span class="StringLit">"owner"</span><span class="Punctuation">,</span> <span class="StringLit">"priority"</span><span class="Punctuation">]</span><span class="Punctuation">)</span></pre><p>will generate the following procedure:</p>
|
||||||
|
<pre class="listing"><span class="Keyword">proc</span> <span class="Identifier">findTodoItemsByOwnerAndPriority</span><span class="Operator">*</span><span class="Punctuation">(</span><span class="Identifier">db</span><span class="Punctuation">:</span> <span class="Identifier">SampleDB</span><span class="Punctuation">,</span>
|
||||||
|
<span class="Identifier">owner</span><span class="Punctuation">:</span> <span class="Identifier">string</span><span class="Punctuation">,</span> <span class="Identifier">priority</span><span class="Punctuation">:</span> <span class="Identifier">int</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">seq</span><span class="Punctuation">[</span><span class="Identifier">TodoItem</span><span class="Punctuation">]</span></pre>
|
||||||
|
<a
|
||||||
|
href="https://github.com/jdbernard/fiber-orm/tree/version-1-6/src/fiber_orm.nim#L468"
|
||||||
|
class="link-seesrc" target="_blank">Source</a>
|
||||||
|
<a href="https://github.com/jdbernard/fiber-orm/edit/devel/src/fiber_orm.nim#L468" class="link-seesrc" target="_blank" >Edit</a>
|
||||||
|
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
<div id="generateProcsForFieldLookups.m,type,openArray[tuple[type,seq[string]]]">
|
||||||
|
<dt><pre><span class="Keyword">macro</span> <a href="#generateProcsForFieldLookups.m%2Ctype%2CopenArray%5Btuple%5Btype%2Cseq%5Bstring%5D%5D%5D"><span class="Identifier">generateProcsForFieldLookups</span></a><span class="Other">(</span><span class="Identifier">dbType</span><span class="Other">:</span> <span class="Identifier">type</span><span class="Other">;</span> <span class="Identifier">modelsAndFields</span><span class="Other">:</span> <span class="Identifier">openArray</span><span class="Other">[</span>
|
||||||
|
<span class="Keyword">tuple</span><span class="Other">[</span><span class="Identifier">t</span><span class="Other">:</span> <span class="Identifier">type</span><span class="Other">,</span> <span class="Identifier">fields</span><span class="Other">:</span> <span class="Identifier">seq</span><span class="Other">[</span><span class="Identifier">string</span><span class="Other">]</span><span class="Other">]</span><span class="Other">]</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">untyped</span></pre></dt>
|
||||||
|
<dd>
|
||||||
|
|
||||||
|
|
||||||
|
<a
|
||||||
|
href="https://github.com/jdbernard/fiber-orm/tree/version-1-6/src/fiber_orm.nim#L510"
|
||||||
|
class="link-seesrc" target="_blank">Source</a>
|
||||||
|
<a href="https://github.com/jdbernard/fiber-orm/edit/devel/src/fiber_orm.nim#L510" class="link-seesrc" target="_blank" >Edit</a>
|
||||||
|
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
<div id="generateProcsForModels.m,type,openArray[type]">
|
||||||
|
<dt><pre><span class="Keyword">macro</span> <a href="#generateProcsForModels.m%2Ctype%2CopenArray%5Btype%5D"><span class="Identifier">generateProcsForModels</span></a><span class="Other">(</span><span class="Identifier">dbType</span><span class="Other">:</span> <span class="Identifier">type</span><span class="Other">;</span> <span class="Identifier">modelTypes</span><span class="Other">:</span> <span class="Identifier">openArray</span><span class="Other">[</span><span class="Identifier">type</span><span class="Other">]</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">untyped</span></pre></dt>
|
||||||
|
<dd>
|
||||||
|
|
||||||
|
Generate all standard access procedures for the given model types. For a <a class="reference external" href="#objectminusrelational-modeling-model-class">model class</a> named <tt class="docutils literal"><span class="pre"><span class="Identifier">TodoItem</span></span></tt>, this will generate the following procedures:<pre class="listing"><span class="Keyword">proc</span> <span class="Identifier">getTodoItem</span><span class="Operator">*</span><span class="Punctuation">(</span><span class="Identifier">db</span><span class="Punctuation">:</span> <span class="Identifier">TodoDB</span><span class="Punctuation">,</span> <span class="Identifier">id</span><span class="Punctuation">:</span> <span class="Identifier">idType</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">TodoItem</span><span class="Punctuation">;</span>
|
||||||
|
<span class="Keyword">proc</span> <span class="Identifier">getAllTodoItems</span><span class="Operator">*</span><span class="Punctuation">(</span><span class="Identifier">db</span><span class="Punctuation">:</span> <span class="Identifier">TodoDB</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">TodoItem</span><span class="Punctuation">;</span>
|
||||||
|
<span class="Keyword">proc</span> <span class="Identifier">createTodoItem</span><span class="Operator">*</span><span class="Punctuation">(</span><span class="Identifier">db</span><span class="Punctuation">:</span> <span class="Identifier">TodoDB</span><span class="Punctuation">,</span> <span class="Identifier">rec</span><span class="Punctuation">:</span> <span class="Identifier">TodoItem</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">TodoItem</span><span class="Punctuation">;</span>
|
||||||
|
<span class="Keyword">proc</span> <span class="Identifier">deleteTodoItem</span><span class="Operator">*</span><span class="Punctuation">(</span><span class="Identifier">db</span><span class="Punctuation">:</span> <span class="Identifier">TodoDB</span><span class="Punctuation">,</span> <span class="Identifier">rec</span><span class="Punctuation">:</span> <span class="Identifier">TodoItem</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">bool</span><span class="Punctuation">;</span>
|
||||||
|
<span class="Keyword">proc</span> <span class="Identifier">deleteTodoItem</span><span class="Operator">*</span><span class="Punctuation">(</span><span class="Identifier">db</span><span class="Punctuation">:</span> <span class="Identifier">TodoDB</span><span class="Punctuation">,</span> <span class="Identifier">id</span><span class="Punctuation">:</span> <span class="Identifier">idType</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">bool</span><span class="Punctuation">;</span>
|
||||||
|
<span class="Keyword">proc</span> <span class="Identifier">updateTodoItem</span><span class="Operator">*</span><span class="Punctuation">(</span><span class="Identifier">db</span><span class="Punctuation">:</span> <span class="Identifier">TodoDB</span><span class="Punctuation">,</span> <span class="Identifier">rec</span><span class="Punctuation">:</span> <span class="Identifier">TodoItem</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">bool</span><span class="Punctuation">;</span>
|
||||||
|
|
||||||
|
<span class="Keyword">proc</span> <span class="Identifier">findTodoItemsWhere</span><span class="Operator">*</span><span class="Punctuation">(</span>
|
||||||
|
<span class="Identifier">db</span><span class="Punctuation">:</span> <span class="Identifier">TodoDB</span><span class="Punctuation">,</span> <span class="Identifier">whereClause</span><span class="Punctuation">:</span> <span class="Identifier">string</span><span class="Punctuation">,</span> <span class="Identifier">values</span><span class="Punctuation">:</span> <span class="Identifier">varargs</span><span class="Punctuation">[</span><span class="Identifier">string</span><span class="Punctuation">]</span><span class="Punctuation">)</span><span class="Punctuation">:</span> <span class="Identifier">TodoItem</span><span class="Punctuation">;</span></pre><p><tt class="docutils literal"><span class="pre"><span class="Identifier">dbType</span></span></tt> is expected to be some type that has a defined <tt class="docutils literal"><span class="pre"><span class="Identifier">withConn</span></span></tt> procedure (see <a class="reference external" href="#database-object">Database Object</a> for details).</p>
|
||||||
|
|
||||||
|
<a
|
||||||
|
href="https://github.com/jdbernard/fiber-orm/tree/version-1-6/src/fiber_orm.nim#L414"
|
||||||
|
class="link-seesrc" target="_blank">Source</a>
|
||||||
|
<a href="https://github.com/jdbernard/fiber-orm/edit/devel/src/fiber_orm.nim#L414" class="link-seesrc" target="_blank" >Edit</a>
|
||||||
|
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</dl></div>
|
||||||
|
<div class="section" id="18">
|
||||||
|
<h1><a class="toc-backref" href="#18">Templates</a></h1>
|
||||||
|
<dl class="item">
|
||||||
|
<div id="deleteRecord.t,DbConn,type,typed">
|
||||||
|
<dt><pre><span class="Keyword">template</span> <a href="#deleteRecord.t%2CDbConn%2Ctype%2Ctyped"><span class="Identifier">deleteRecord</span></a><span class="Other">(</span><span class="Identifier">db</span><span class="Other">:</span> <span class="Identifier">DbConn</span><span class="Other">;</span> <span class="Identifier">modelType</span><span class="Other">:</span> <span class="Identifier">type</span><span class="Other">;</span> <span class="Identifier">id</span><span class="Other">:</span> <span class="Identifier">typed</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">untyped</span></pre></dt>
|
||||||
|
<dd>
|
||||||
|
|
||||||
|
Delete a record by id.
|
||||||
|
<a
|
||||||
|
href="https://github.com/jdbernard/fiber-orm/tree/version-1-6/src/fiber_orm.nim#L353"
|
||||||
|
class="link-seesrc" target="_blank">Source</a>
|
||||||
|
<a href="https://github.com/jdbernard/fiber-orm/edit/devel/src/fiber_orm.nim#L353" class="link-seesrc" target="_blank" >Edit</a>
|
||||||
|
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
<div id="findRecordsBy.t,DbConn,type,seq[tuple[string,string]]">
|
||||||
|
<dt><pre><span class="Keyword">template</span> <a href="#findRecordsBy.t%2CDbConn%2Ctype%2Cseq%5Btuple%5Bstring%2Cstring%5D%5D"><span class="Identifier">findRecordsBy</span></a><span class="Other">(</span><span class="Identifier">db</span><span class="Other">:</span> <span class="Identifier">DbConn</span><span class="Other">;</span> <span class="Identifier">modelType</span><span class="Other">:</span> <span class="Identifier">type</span><span class="Other">;</span>
|
||||||
|
<span class="Identifier">lookups</span><span class="Other">:</span> <span class="Identifier">seq</span><span class="Other">[</span><span class="Keyword">tuple</span><span class="Other">[</span><span class="Identifier">field</span><span class="Other">:</span> <span class="Identifier">string</span><span class="Other">,</span> <span class="Identifier">value</span><span class="Other">:</span> <span class="Identifier">string</span><span class="Other">]</span><span class="Other">]</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">untyped</span></pre></dt>
|
||||||
|
<dd>
|
||||||
|
|
||||||
|
Find all records matching the provided lookup values.
|
||||||
|
<a
|
||||||
|
href="https://github.com/jdbernard/fiber-orm/tree/version-1-6/src/fiber_orm.nim#L403"
|
||||||
|
class="link-seesrc" target="_blank">Source</a>
|
||||||
|
<a href="https://github.com/jdbernard/fiber-orm/edit/devel/src/fiber_orm.nim#L403" class="link-seesrc" target="_blank" >Edit</a>
|
||||||
|
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
<div id="findRecordsWhere.t,DbConn,type,string,varargs[string,dbFormat]">
|
||||||
|
<dt><pre><span class="Keyword">template</span> <a href="#findRecordsWhere.t%2CDbConn%2Ctype%2Cstring%2Cvarargs%5Bstring%2CdbFormat%5D"><span class="Identifier">findRecordsWhere</span></a><span class="Other">(</span><span class="Identifier">db</span><span class="Other">:</span> <span class="Identifier">DbConn</span><span class="Other">;</span> <span class="Identifier">modelType</span><span class="Other">:</span> <span class="Identifier">type</span><span class="Other">;</span> <span class="Identifier">whereClause</span><span class="Other">:</span> <span class="Identifier">string</span><span class="Other">;</span>
|
||||||
|
<span class="Identifier">values</span><span class="Other">:</span> <span class="Identifier">varargs</span><span class="Other">[</span><span class="Identifier">string</span><span class="Other">,</span> <span class="Identifier">dbFormat</span><span class="Other">]</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">untyped</span></pre></dt>
|
||||||
|
<dd>
|
||||||
|
|
||||||
|
Find all records matching a given <tt class="docutils literal"><span class="pre"><span class="Identifier">WHERE</span></span></tt> clause. The number of elements in the <tt class="docutils literal"><span class="pre"><span class="Identifier">values</span></span></tt> array must match the number of placeholders (<tt class="docutils literal"><span class="pre"><span class="Operator">?</span></span></tt>) in the provided <tt class="docutils literal"><span class="pre"><span class="Identifier">WHERE</span></span></tt> clause.
|
||||||
|
<a
|
||||||
|
href="https://github.com/jdbernard/fiber-orm/tree/version-1-6/src/fiber_orm.nim#L382"
|
||||||
|
class="link-seesrc" target="_blank">Source</a>
|
||||||
|
<a href="https://github.com/jdbernard/fiber-orm/edit/devel/src/fiber_orm.nim#L382" class="link-seesrc" target="_blank" >Edit</a>
|
||||||
|
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
<div id="getAllRecords.t,DbConn,type">
|
||||||
|
<dt><pre><span class="Keyword">template</span> <a href="#getAllRecords.t%2CDbConn%2Ctype"><span class="Identifier">getAllRecords</span></a><span class="Other">(</span><span class="Identifier">db</span><span class="Other">:</span> <span class="Identifier">DbConn</span><span class="Other">;</span> <span class="Identifier">modelType</span><span class="Other">:</span> <span class="Identifier">type</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">untyped</span></pre></dt>
|
||||||
|
<dd>
|
||||||
|
|
||||||
|
Fetch all records of the given type.
|
||||||
|
<a
|
||||||
|
href="https://github.com/jdbernard/fiber-orm/tree/version-1-6/src/fiber_orm.nim#L394"
|
||||||
|
class="link-seesrc" target="_blank">Source</a>
|
||||||
|
<a href="https://github.com/jdbernard/fiber-orm/edit/devel/src/fiber_orm.nim#L394" class="link-seesrc" target="_blank" >Edit</a>
|
||||||
|
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
<div id="getRecord.t,DbConn,type,typed">
|
||||||
|
<dt><pre><span class="Keyword">template</span> <a href="#getRecord.t%2CDbConn%2Ctype%2Ctyped"><span class="Identifier">getRecord</span></a><span class="Other">(</span><span class="Identifier">db</span><span class="Other">:</span> <span class="Identifier">DbConn</span><span class="Other">;</span> <span class="Identifier">modelType</span><span class="Other">:</span> <span class="Identifier">type</span><span class="Other">;</span> <span class="Identifier">id</span><span class="Other">:</span> <span class="Identifier">typed</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">untyped</span></pre></dt>
|
||||||
|
<dd>
|
||||||
|
|
||||||
|
Fetch a record by id.
|
||||||
|
<a
|
||||||
|
href="https://github.com/jdbernard/fiber-orm/tree/version-1-6/src/fiber_orm.nim#L367"
|
||||||
|
class="link-seesrc" target="_blank">Source</a>
|
||||||
|
<a href="https://github.com/jdbernard/fiber-orm/edit/devel/src/fiber_orm.nim#L367" class="link-seesrc" target="_blank" >Edit</a>
|
||||||
|
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
<div id="inTransaction.t,DbConnPool,untyped">
|
||||||
|
<dt><pre><span class="Keyword">template</span> <a href="#inTransaction.t%2CDbConnPool%2Cuntyped"><span class="Identifier">inTransaction</span></a><span class="Other">(</span><span class="Identifier">db</span><span class="Other">:</span> <a href="fiber_orm/pool.html#DbConnPool"><span class="Identifier">DbConnPool</span></a><span class="Other">;</span> <span class="Identifier">body</span><span class="Other">:</span> <span class="Identifier">untyped</span><span class="Other">)</span></pre></dt>
|
||||||
|
<dd>
|
||||||
|
|
||||||
|
|
||||||
|
<a
|
||||||
|
href="https://github.com/jdbernard/fiber-orm/tree/version-1-6/src/fiber_orm.nim#L567"
|
||||||
|
class="link-seesrc" target="_blank">Source</a>
|
||||||
|
<a href="https://github.com/jdbernard/fiber-orm/edit/devel/src/fiber_orm.nim#L567" class="link-seesrc" target="_blank" >Edit</a>
|
||||||
|
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</dl></div>
|
||||||
|
<div class="section" id="19">
|
||||||
|
<h1><a class="toc-backref" href="#19">Exports</a></h1>
|
||||||
|
<dl class="item">
|
||||||
|
<a href="fiber_orm/pool.html#DbConnPoolConfig"><span class="Identifier">DbConnPoolConfig</span></a>, <a href="fiber_orm/pool.html#initDbConnPool,DbConnPoolConfig"><span class="Identifier">initDbConnPool</span></a>, <a href="fiber_orm/pool.html#withConn.t,DbConnPool,untyped"><span class="Identifier">withConn</span></a>, <a href="fiber_orm/pool.html#take,DbConnPool"><span class="Identifier">take</span></a>, <a href="fiber_orm/pool.html#DbConnPool"><span class="Identifier">DbConnPool</span></a>, <a href="fiber_orm/pool.html#release,DbConnPool,int"><span class="Identifier">release</span></a>, <a href="fiber_orm/util.html#columnNamesForModel.m,typed"><span class="Identifier">columnNamesForModel</span></a>, <a href="fiber_orm/util.html#dbFormat,DateTime"><span class="Identifier">dbFormat</span></a>, <a href="fiber_orm/util.html#dbFormat,seq[T]"><span class="Identifier">dbFormat</span></a>, <a href="fiber_orm/util.html#dbFormat,string"><span class="Identifier">dbFormat</span></a>, <a href="fiber_orm/util.html#dbFormat,T"><span class="Identifier">dbFormat</span></a>, <a href="fiber_orm/util.html#dbNameToIdent,string"><span class="Identifier">dbNameToIdent</span></a>, <a href="fiber_orm/util.html#identNameToDb,string"><span class="Identifier">identNameToDb</span></a>, <a href="fiber_orm/util.html#modelName.m,type"><span class="Identifier">modelName</span></a>, <a href="fiber_orm/util.html#modelName.m"><span class="Identifier">modelName</span></a>, <a href="fiber_orm/util.html#rowToModel.m,typed,seq[string]"><span class="Identifier">rowToModel</span></a>, <a href="fiber_orm/util.html#tableName,type"><span class="Identifier">tableName</span></a>, <a href="fiber_orm/util.html#tableName,T"><span class="Identifier">tableName</span></a>
|
||||||
|
</dl></div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="twelve-columns footer">
|
||||||
|
<span class="nim-sprite"></span>
|
||||||
|
<br/>
|
||||||
|
<small style="color: var(--hint);">Made with Nim. Generated: 2022-09-04 02:31:20 UTC</small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
1016
docs/nimdoc.out.css
Normal file
1016
docs/nimdoc.out.css
Normal file
File diff suppressed because one or more lines are too long
246
docs/theindex.html
Normal file
246
docs/theindex.html
Normal file
@ -0,0 +1,246 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
||||||
|
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||||
|
<!-- This file is generated by Nim. -->
|
||||||
|
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||||
|
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
|
||||||
|
<!-- Favicon -->
|
||||||
|
<link rel="shortcut icon" href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAUAAAAF////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAIAAABbAAAAlQAAAKIAAACbAAAAmwAAAKIAAACVAAAAWwAAAAL///8A////AP///wD///8A////AAAAABQAAADAAAAAYwAAAA3///8A////AP///wD///8AAAAADQAAAGMAAADAAAAAFP///wD///8A////AP///wAAAACdAAAAOv///wD///8A////AP///wD///8A////AP///wD///8AAAAAOgAAAJ3///8A////AP///wAAAAAnAAAAcP///wAAAAAoAAAASv///wD///8A////AP///wAAAABKAAAAKP///wAAAABwAAAAJ////wD///8AAAAAgQAAABwAAACIAAAAkAAAAJMAAACtAAAAFQAAABUAAACtAAAAkwAAAJAAAACIAAAAHAAAAIH///8A////AAAAAKQAAACrAAAAaP///wD///8AAAAARQAAANIAAADSAAAARf///wD///8AAAAAaAAAAKsAAACk////AAAAADMAAACcAAAAnQAAABj///8A////AP///wAAAAAYAAAAGP///wD///8A////AAAAABgAAACdAAAAnAAAADMAAAB1AAAAwwAAAP8AAADpAAAAsQAAAE4AAAAb////AP///wAAAAAbAAAATgAAALEAAADpAAAA/wAAAMMAAAB1AAAAtwAAAOkAAAD/AAAA/wAAAP8AAADvAAAA3gAAAN4AAADeAAAA3gAAAO8AAAD/AAAA/wAAAP8AAADpAAAAtwAAAGUAAAA/AAAA3wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAADfAAAAPwAAAGX///8A////AAAAAEgAAADtAAAAvwAAAL0AAADGAAAA7wAAAO8AAADGAAAAvQAAAL8AAADtAAAASP///wD///8A////AP///wD///8AAAAAO////wD///8A////AAAAAIcAAACH////AP///wD///8AAAAAO////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A//8AAP//AAD4HwAA7/cAAN/7AAD//wAAoYUAAJ55AACf+QAAh+EAAAAAAADAAwAA4AcAAP5/AAD//wAA//8AAA=="/>
|
||||||
|
<link rel="icon" type="image/png" sizes="32x32" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAA3XAAAN1wFCKJt4AAAAB3RJTUUH4QQQEwksSS9ZWwAAAk1JREFUWMPtll2ITVEUx39nn/O7Y5qR8f05wtCUUr6ZIS++8pEnkZInPImneaCQ5METNdOkeFBKUhMPRIkHKfEuUZSUlGlKPN2TrgfncpvmnntnmlEyq1Z7t89/rf9a6+y99oZxGZf/XeIq61EdtgKXgdXA0xrYAvBjOIF1AI9zvjcC74BSpndrJPkBWDScTF8Aa4E3wDlgHbASaANmVqlcCnwHvgDvgVfAJ+AikAAvgfVZwLnSVZHZaOuKoQi3ZOMi4NkYkpe1p4J7A8BpYAD49hfIy/oqG0+hLomiKP2L5L+1ubn5115S+3OAn4EnwBlgMzCjyt6ZAnQCJ4A7wOs88iRJHvw50HoujuPBoCKwHWiosy8MdfZnAdcHk8dxXFJ3VQbQlCTJvRBCGdRbD4M6uc5glpY3eAihpN5S5w12diSEcCCEcKUO4ljdr15T76ur1FDDLIQQ3qv71EdDOe3Kxj3leRXyk+pxdWnFWod6Wt2bY3de3aSuUHcPBVimHs7mK9WrmeOF6lR1o9qnzskh2ar2qm1qizpfXaPeVGdlmGN5pb09qMxz1Xb1kLqgzn1RyH7JUXW52lr5e/Kqi9qpto7V1atuUzfnARrV7jEib1T76gG2qxdGmXyiekkt1GswPTtek0aBfJp6YySGBfWg2tPQ0FAYgf1stUfdmdcjarbYJEniKIq6gY/Aw+zWHAC+p2labGpqiorFYgGYCEzN7oQdQClN07O1/EfDyGgC0ALMBdYAi4FyK+4H3gLPsxfR1zRNi+NP7nH5J+QntnXe5B5mpfQAAAAASUVORK5CYII=">
|
||||||
|
|
||||||
|
<!-- Google fonts -->
|
||||||
|
<link href='https://fonts.googleapis.com/css?family=Lato:400,600,900' rel='stylesheet' type='text/css'/>
|
||||||
|
<link href='https://fonts.googleapis.com/css?family=Source+Code+Pro:400,500,600' rel='stylesheet' type='text/css'/>
|
||||||
|
|
||||||
|
<!-- CSS -->
|
||||||
|
<title>Index</title>
|
||||||
|
<link rel="stylesheet" type="text/css" href="nimdoc.out.css">
|
||||||
|
|
||||||
|
<script type="text/javascript" src="dochack.js"></script>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
function main() {
|
||||||
|
var pragmaDots = document.getElementsByClassName("pragmadots");
|
||||||
|
for (var i = 0; i < pragmaDots.length; i++) {
|
||||||
|
pragmaDots[i].onclick = function(event) {
|
||||||
|
// Hide tease
|
||||||
|
event.target.parentNode.style.display = "none";
|
||||||
|
// Show actual
|
||||||
|
event.target.parentNode.nextElementSibling.style.display = "inline";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function switchTheme(e) {
|
||||||
|
if (e.target.checked) {
|
||||||
|
document.documentElement.setAttribute('data-theme', 'dark');
|
||||||
|
localStorage.setItem('theme', 'dark');
|
||||||
|
} else {
|
||||||
|
document.documentElement.setAttribute('data-theme', 'light');
|
||||||
|
localStorage.setItem('theme', 'light');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const toggleSwitch = document.querySelector('.theme-switch input[type="checkbox"]');
|
||||||
|
if (toggleSwitch !== null) {
|
||||||
|
toggleSwitch.addEventListener('change', switchTheme, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
var currentTheme = localStorage.getItem('theme');
|
||||||
|
if (!currentTheme && window.matchMedia('(prefers-color-scheme: dark)').matches) {
|
||||||
|
currentTheme = 'dark';
|
||||||
|
}
|
||||||
|
if (currentTheme) {
|
||||||
|
document.documentElement.setAttribute('data-theme', currentTheme);
|
||||||
|
|
||||||
|
if (currentTheme === 'dark' && toggleSwitch !== null) {
|
||||||
|
toggleSwitch.checked = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener('DOMContentLoaded', main);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="document" id="documentId">
|
||||||
|
<div class="container">
|
||||||
|
<h1 class="title">Index</h1>
|
||||||
|
Modules: <a href="fiber_orm.html">fiber_orm</a>, <a href="fiber_orm/pool.html">fiber_orm/pool</a>, <a href="fiber_orm/util.html">fiber_orm/util</a>.<br/><p /><h2>API symbols</h2>
|
||||||
|
<dl><dt><a name="columnNamesForModel" href="#columnNamesForModel"><span>columnNamesForModel:</span></a></dt><dd><ul class="simple">
|
||||||
|
<li><a class="reference external"
|
||||||
|
data-doc-search-tag="util: columnNamesForModel(modelType: typed): seq[string]" href="fiber_orm/util.html#columnNamesForModel.m%2Ctyped">util: columnNamesForModel(modelType: typed): seq[string]</a></li>
|
||||||
|
</ul></dd>
|
||||||
|
<dt><a name="createParseStmt" href="#createParseStmt"><span>createParseStmt:</span></a></dt><dd><ul class="simple">
|
||||||
|
<li><a class="reference external"
|
||||||
|
data-doc-search-tag="util: createParseStmt(t, value: NimNode): NimNode" href="fiber_orm/util.html#createParseStmt%2CNimNode%2CNimNode">util: createParseStmt(t, value: NimNode): NimNode</a></li>
|
||||||
|
</ul></dd>
|
||||||
|
<dt><a name="createRecord" href="#createRecord"><span>createRecord:</span></a></dt><dd><ul class="simple">
|
||||||
|
<li><a class="reference external"
|
||||||
|
data-doc-search-tag="fiber_orm: createRecord[T](db: DbConn; rec: T): T" href="fiber_orm.html#createRecord%2CDbConn%2CT">fiber_orm: createRecord[T](db: DbConn; rec: T): T</a></li>
|
||||||
|
</ul></dd>
|
||||||
|
<dt><a name="DbConnPool" href="#DbConnPool"><span>DbConnPool:</span></a></dt><dd><ul class="simple">
|
||||||
|
<li><a class="reference external"
|
||||||
|
data-doc-search-tag="pool: DbConnPool" href="fiber_orm/pool.html#DbConnPool">pool: DbConnPool</a></li>
|
||||||
|
</ul></dd>
|
||||||
|
<dt><a name="DbConnPoolConfig" href="#DbConnPoolConfig"><span>DbConnPoolConfig:</span></a></dt><dd><ul class="simple">
|
||||||
|
<li><a class="reference external"
|
||||||
|
data-doc-search-tag="pool: DbConnPoolConfig" href="fiber_orm/pool.html#DbConnPoolConfig">pool: DbConnPoolConfig</a></li>
|
||||||
|
</ul></dd>
|
||||||
|
<dt><a name="dbFormat" href="#dbFormat"><span>dbFormat:</span></a></dt><dd><ul class="simple">
|
||||||
|
<li><a class="reference external"
|
||||||
|
data-doc-search-tag="util: dbFormat(dt: DateTime): string" href="fiber_orm/util.html#dbFormat%2CDateTime">util: dbFormat(dt: DateTime): string</a></li>
|
||||||
|
<li><a class="reference external"
|
||||||
|
data-doc-search-tag="util: dbFormat[T](list: seq[T]): string" href="fiber_orm/util.html#dbFormat%2Cseq%5BT%5D">util: dbFormat[T](list: seq[T]): string</a></li>
|
||||||
|
<li><a class="reference external"
|
||||||
|
data-doc-search-tag="util: dbFormat(s: string): string" href="fiber_orm/util.html#dbFormat%2Cstring">util: dbFormat(s: string): string</a></li>
|
||||||
|
<li><a class="reference external"
|
||||||
|
data-doc-search-tag="util: dbFormat[T](item: T): string" href="fiber_orm/util.html#dbFormat%2CT">util: dbFormat[T](item: T): string</a></li>
|
||||||
|
</ul></dd>
|
||||||
|
<dt><a name="dbNameToIdent" href="#dbNameToIdent"><span>dbNameToIdent:</span></a></dt><dd><ul class="simple">
|
||||||
|
<li><a class="reference external"
|
||||||
|
data-doc-search-tag="util: dbNameToIdent(name: string): string" href="fiber_orm/util.html#dbNameToIdent%2Cstring">util: dbNameToIdent(name: string): string</a></li>
|
||||||
|
</ul></dd>
|
||||||
|
<dt><a name="deleteRecord" href="#deleteRecord"><span>deleteRecord:</span></a></dt><dd><ul class="simple">
|
||||||
|
<li><a class="reference external"
|
||||||
|
data-doc-search-tag="fiber_orm: deleteRecord[T](db: DbConn; rec: T): bool" href="fiber_orm.html#deleteRecord%2CDbConn%2CT">fiber_orm: deleteRecord[T](db: DbConn; rec: T): bool</a></li>
|
||||||
|
<li><a class="reference external"
|
||||||
|
data-doc-search-tag="fiber_orm: deleteRecord(db: DbConn; modelType: type; id: typed): untyped" href="fiber_orm.html#deleteRecord.t%2CDbConn%2Ctype%2Ctyped">fiber_orm: deleteRecord(db: DbConn; modelType: type; id: typed): untyped</a></li>
|
||||||
|
</ul></dd>
|
||||||
|
<dt><a name="findRecordsBy" href="#findRecordsBy"><span>findRecordsBy:</span></a></dt><dd><ul class="simple">
|
||||||
|
<li><a class="reference external"
|
||||||
|
data-doc-search-tag="fiber_orm: findRecordsBy(db: DbConn; modelType: type;
|
||||||
|
lookups: seq[tuple[field: string, value: string]]): untyped" href="fiber_orm.html#findRecordsBy.t%2CDbConn%2Ctype%2Cseq%5Btuple%5Bstring%2Cstring%5D%5D">fiber_orm: findRecordsBy(db: DbConn; modelType: type;
|
||||||
|
lookups: seq[tuple[field: string, value: string]]): untyped</a></li>
|
||||||
|
</ul></dd>
|
||||||
|
<dt><a name="findRecordsWhere" href="#findRecordsWhere"><span>findRecordsWhere:</span></a></dt><dd><ul class="simple">
|
||||||
|
<li><a class="reference external"
|
||||||
|
data-doc-search-tag="fiber_orm: findRecordsWhere(db: DbConn; modelType: type; whereClause: string;
|
||||||
|
values: varargs[string, dbFormat]): untyped" href="fiber_orm.html#findRecordsWhere.t%2CDbConn%2Ctype%2Cstring%2Cvarargs%5Bstring%2CdbFormat%5D">fiber_orm: findRecordsWhere(db: DbConn; modelType: type; whereClause: string;
|
||||||
|
values: varargs[string, dbFormat]): untyped</a></li>
|
||||||
|
</ul></dd>
|
||||||
|
<dt><a name="generateLookup" href="#generateLookup"><span>generateLookup:</span></a></dt><dd><ul class="simple">
|
||||||
|
<li><a class="reference external"
|
||||||
|
data-doc-search-tag="fiber_orm: generateLookup(dbType: type; modelType: type; fields: seq[string]): untyped" href="fiber_orm.html#generateLookup.m%2Ctype%2Ctype%2Cseq%5Bstring%5D">fiber_orm: generateLookup(dbType: type; modelType: type; fields: seq[string]): untyped</a></li>
|
||||||
|
</ul></dd>
|
||||||
|
<dt><a name="generateProcsForFieldLookups" href="#generateProcsForFieldLookups"><span>generateProcsForFieldLookups:</span></a></dt><dd><ul class="simple">
|
||||||
|
<li><a class="reference external"
|
||||||
|
data-doc-search-tag="fiber_orm: generateProcsForFieldLookups(dbType: type; modelsAndFields: openArray[
|
||||||
|
tuple[t: type, fields: seq[string]]]): untyped" href="fiber_orm.html#generateProcsForFieldLookups.m%2Ctype%2CopenArray%5Btuple%5Btype%2Cseq%5Bstring%5D%5D%5D">fiber_orm: generateProcsForFieldLookups(dbType: type; modelsAndFields: openArray[
|
||||||
|
tuple[t: type, fields: seq[string]]]): untyped</a></li>
|
||||||
|
</ul></dd>
|
||||||
|
<dt><a name="generateProcsForModels" href="#generateProcsForModels"><span>generateProcsForModels:</span></a></dt><dd><ul class="simple">
|
||||||
|
<li><a class="reference external"
|
||||||
|
data-doc-search-tag="fiber_orm: generateProcsForModels(dbType: type; modelTypes: openArray[type]): untyped" href="fiber_orm.html#generateProcsForModels.m%2Ctype%2CopenArray%5Btype%5D">fiber_orm: generateProcsForModels(dbType: type; modelTypes: openArray[type]): untyped</a></li>
|
||||||
|
</ul></dd>
|
||||||
|
<dt><a name="getAllRecords" href="#getAllRecords"><span>getAllRecords:</span></a></dt><dd><ul class="simple">
|
||||||
|
<li><a class="reference external"
|
||||||
|
data-doc-search-tag="fiber_orm: getAllRecords(db: DbConn; modelType: type): untyped" href="fiber_orm.html#getAllRecords.t%2CDbConn%2Ctype">fiber_orm: getAllRecords(db: DbConn; modelType: type): untyped</a></li>
|
||||||
|
</ul></dd>
|
||||||
|
<dt><a name="getRecord" href="#getRecord"><span>getRecord:</span></a></dt><dd><ul class="simple">
|
||||||
|
<li><a class="reference external"
|
||||||
|
data-doc-search-tag="fiber_orm: getRecord(db: DbConn; modelType: type; id: typed): untyped" href="fiber_orm.html#getRecord.t%2CDbConn%2Ctype%2Ctyped">fiber_orm: getRecord(db: DbConn; modelType: type; id: typed): untyped</a></li>
|
||||||
|
</ul></dd>
|
||||||
|
<dt><a name="identNameToDb" href="#identNameToDb"><span>identNameToDb:</span></a></dt><dd><ul class="simple">
|
||||||
|
<li><a class="reference external"
|
||||||
|
data-doc-search-tag="util: identNameToDb(name: string): string" href="fiber_orm/util.html#identNameToDb%2Cstring">util: identNameToDb(name: string): string</a></li>
|
||||||
|
</ul></dd>
|
||||||
|
<dt><a name="initDbConnPool" href="#initDbConnPool"><span>initDbConnPool:</span></a></dt><dd><ul class="simple">
|
||||||
|
<li><a class="reference external"
|
||||||
|
data-doc-search-tag="pool: initDbConnPool(cfg: DbConnPoolConfig): DbConnPool" href="fiber_orm/pool.html#initDbConnPool%2CDbConnPoolConfig">pool: initDbConnPool(cfg: DbConnPoolConfig): DbConnPool</a></li>
|
||||||
|
</ul></dd>
|
||||||
|
<dt><a name="initPool" href="#initPool"><span>initPool:</span></a></dt><dd><ul class="simple">
|
||||||
|
<li><a class="reference external"
|
||||||
|
data-doc-search-tag="fiber_orm: initPool(connect: proc (): DbConn; poolSize = 10; hardCap = false;
|
||||||
|
healthCheckQuery = "SELECT \'true\' AS alive"): DbConnPool" href="fiber_orm.html#initPool%2Cproc%29%2Cint%2Cstring">fiber_orm: initPool(connect: proc (): DbConn; poolSize = 10; hardCap = false;
|
||||||
|
healthCheckQuery = "SELECT \'true\' AS alive"): DbConnPool</a></li>
|
||||||
|
</ul></dd>
|
||||||
|
<dt><a name="inTransaction" href="#inTransaction"><span>inTransaction:</span></a></dt><dd><ul class="simple">
|
||||||
|
<li><a class="reference external"
|
||||||
|
data-doc-search-tag="fiber_orm: inTransaction(db: DbConnPool; body: untyped)" href="fiber_orm.html#inTransaction.t%2CDbConnPool%2Cuntyped">fiber_orm: inTransaction(db: DbConnPool; body: untyped)</a></li>
|
||||||
|
</ul></dd>
|
||||||
|
<dt><a name="listFields" href="#listFields"><span>listFields:</span></a></dt><dd><ul class="simple">
|
||||||
|
<li><a class="reference external"
|
||||||
|
data-doc-search-tag="util: listFields(t: typed): untyped" href="fiber_orm/util.html#listFields.m%2Ctyped">util: listFields(t: typed): untyped</a></li>
|
||||||
|
</ul></dd>
|
||||||
|
<dt><a name="modelName" href="#modelName"><span>modelName:</span></a></dt><dd><ul class="simple">
|
||||||
|
<li><a class="reference external"
|
||||||
|
data-doc-search-tag="util: modelName(model: object): string" href="fiber_orm/util.html#modelName.m">util: modelName(model: object): string</a></li>
|
||||||
|
<li><a class="reference external"
|
||||||
|
data-doc-search-tag="util: modelName(modelType: type): string" href="fiber_orm/util.html#modelName.m%2Ctype">util: modelName(modelType: type): string</a></li>
|
||||||
|
</ul></dd>
|
||||||
|
<dt><a name="MutateClauses" href="#MutateClauses"><span>MutateClauses:</span></a></dt><dd><ul class="simple">
|
||||||
|
<li><a class="reference external"
|
||||||
|
data-doc-search-tag="util: MutateClauses" href="fiber_orm/util.html#MutateClauses">util: MutateClauses</a></li>
|
||||||
|
</ul></dd>
|
||||||
|
<dt><a name="NotFoundError" href="#NotFoundError"><span>NotFoundError:</span></a></dt><dd><ul class="simple">
|
||||||
|
<li><a class="reference external"
|
||||||
|
data-doc-search-tag="fiber_orm: NotFoundError" href="fiber_orm.html#NotFoundError">fiber_orm: NotFoundError</a></li>
|
||||||
|
</ul></dd>
|
||||||
|
<dt><a name="parseDbArray" href="#parseDbArray"><span>parseDbArray:</span></a></dt><dd><ul class="simple">
|
||||||
|
<li><a class="reference external"
|
||||||
|
data-doc-search-tag="util: parseDbArray(val: string): seq[string]" href="fiber_orm/util.html#parseDbArray%2Cstring">util: parseDbArray(val: string): seq[string]</a></li>
|
||||||
|
</ul></dd>
|
||||||
|
<dt><a name="parsePGDatetime" href="#parsePGDatetime"><span>parsePGDatetime:</span></a></dt><dd><ul class="simple">
|
||||||
|
<li><a class="reference external"
|
||||||
|
data-doc-search-tag="util: parsePGDatetime(val: string): DateTime" href="fiber_orm/util.html#parsePGDatetime%2Cstring">util: parsePGDatetime(val: string): DateTime</a></li>
|
||||||
|
</ul></dd>
|
||||||
|
<dt><a name="pluralize" href="#pluralize"><span>pluralize:</span></a></dt><dd><ul class="simple">
|
||||||
|
<li><a class="reference external"
|
||||||
|
data-doc-search-tag="util: pluralize(name: string): string" href="fiber_orm/util.html#pluralize%2Cstring">util: pluralize(name: string): string</a></li>
|
||||||
|
</ul></dd>
|
||||||
|
<dt><a name="populateMutateClauses" href="#populateMutateClauses"><span>populateMutateClauses:</span></a></dt><dd><ul class="simple">
|
||||||
|
<li><a class="reference external"
|
||||||
|
data-doc-search-tag="util: populateMutateClauses(t: typed; newRecord: bool; mc: var MutateClauses): untyped" href="fiber_orm/util.html#populateMutateClauses.m%2Ctyped%2Cbool%2CMutateClauses">util: populateMutateClauses(t: typed; newRecord: bool; mc: var MutateClauses): untyped</a></li>
|
||||||
|
</ul></dd>
|
||||||
|
<dt><a name="release" href="#release"><span>release:</span></a></dt><dd><ul class="simple">
|
||||||
|
<li><a class="reference external"
|
||||||
|
data-doc-search-tag="pool: release(pool: DbConnPool; connId: int): void" href="fiber_orm/pool.html#release%2CDbConnPool%2Cint">pool: release(pool: DbConnPool; connId: int): void</a></li>
|
||||||
|
</ul></dd>
|
||||||
|
<dt><a name="rowToModel" href="#rowToModel"><span>rowToModel:</span></a></dt><dd><ul class="simple">
|
||||||
|
<li><a class="reference external"
|
||||||
|
data-doc-search-tag="util: rowToModel(modelType: typed; row: seq[string]): untyped" href="fiber_orm/util.html#rowToModel.m%2Ctyped%2Cseq%5Bstring%5D">util: rowToModel(modelType: typed; row: seq[string]): untyped</a></li>
|
||||||
|
</ul></dd>
|
||||||
|
<dt><a name="tableName" href="#tableName"><span>tableName:</span></a></dt><dd><ul class="simple">
|
||||||
|
<li><a class="reference external"
|
||||||
|
data-doc-search-tag="util: tableName[T](rec: T): string" href="fiber_orm/util.html#tableName%2CT">util: tableName[T](rec: T): string</a></li>
|
||||||
|
<li><a class="reference external"
|
||||||
|
data-doc-search-tag="util: tableName(modelType: type): string" href="fiber_orm/util.html#tableName%2Ctype">util: tableName(modelType: type): string</a></li>
|
||||||
|
</ul></dd>
|
||||||
|
<dt><a name="take" href="#take"><span>take:</span></a></dt><dd><ul class="simple">
|
||||||
|
<li><a class="reference external"
|
||||||
|
data-doc-search-tag="pool: take(pool: DbConnPool): tuple[id: int, conn: DbConn]" href="fiber_orm/pool.html#take%2CDbConnPool">pool: take(pool: DbConnPool): tuple[id: int, conn: DbConn]</a></li>
|
||||||
|
</ul></dd>
|
||||||
|
<dt><a name="typeOfColumn" href="#typeOfColumn"><span>typeOfColumn:</span></a></dt><dd><ul class="simple">
|
||||||
|
<li><a class="reference external"
|
||||||
|
data-doc-search-tag="util: typeOfColumn(modelType: NimNode; colName: string): NimNode" href="fiber_orm/util.html#typeOfColumn%2CNimNode%2Cstring">util: typeOfColumn(modelType: NimNode; colName: string): NimNode</a></li>
|
||||||
|
</ul></dd>
|
||||||
|
<dt><a name="updateRecord" href="#updateRecord"><span>updateRecord:</span></a></dt><dd><ul class="simple">
|
||||||
|
<li><a class="reference external"
|
||||||
|
data-doc-search-tag="fiber_orm: updateRecord[T](db: DbConn; rec: T): bool" href="fiber_orm.html#updateRecord%2CDbConn%2CT">fiber_orm: updateRecord[T](db: DbConn; rec: T): bool</a></li>
|
||||||
|
</ul></dd>
|
||||||
|
<dt><a name="walkFieldDefs" href="#walkFieldDefs"><span>walkFieldDefs:</span></a></dt><dd><ul class="simple">
|
||||||
|
<li><a class="reference external"
|
||||||
|
data-doc-search-tag="util: walkFieldDefs(t: NimNode; body: untyped)" href="fiber_orm/util.html#walkFieldDefs.t%2CNimNode%2Cuntyped">util: walkFieldDefs(t: NimNode; body: untyped)</a></li>
|
||||||
|
</ul></dd>
|
||||||
|
<dt><a name="withConn" href="#withConn"><span>withConn:</span></a></dt><dd><ul class="simple">
|
||||||
|
<li><a class="reference external"
|
||||||
|
data-doc-search-tag="pool: withConn(pool: DbConnPool; stmt: untyped): untyped" href="fiber_orm/pool.html#withConn.t%2CDbConnPool%2Cuntyped">pool: withConn(pool: DbConnPool; stmt: untyped): untyped</a></li>
|
||||||
|
</ul></dd>
|
||||||
|
</dl>
|
||||||
|
<div class="row">
|
||||||
|
<div class="twelve-columns footer">
|
||||||
|
<span class="nim-sprite"></span>
|
||||||
|
<br/>
|
||||||
|
<small style="color: var(--hint);">Made with Nim. Generated: 2022-09-04 02:31:20 UTC</small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -1,6 +1,6 @@
|
|||||||
# Package
|
# Package
|
||||||
|
|
||||||
version = "0.1.2"
|
version = "3.1.1"
|
||||||
author = "Jonathan Bernard"
|
author = "Jonathan Bernard"
|
||||||
description = "Lightweight Postgres ORM for Nim."
|
description = "Lightweight Postgres ORM for Nim."
|
||||||
license = "GPL-3.0"
|
license = "GPL-3.0"
|
||||||
@ -10,4 +10,5 @@ srcDir = "src"
|
|||||||
|
|
||||||
# Dependencies
|
# Dependencies
|
||||||
|
|
||||||
requires "nim >= 1.0.4"
|
requires @["nim >= 1.4.0", "uuids"]
|
||||||
|
requires "namespaced_logging >= 1.0.0"
|
||||||
|
@ -1,10 +1,327 @@
|
|||||||
import db_postgres, macros, options, sequtils, strutils, uuids
|
# Fiber ORM
|
||||||
|
#
|
||||||
|
# Copyright 2019-2024 Jonathan Bernard <jonathan@jdbernard.com>
|
||||||
|
|
||||||
from unicode import capitalize
|
## Lightweight ORM supporting the `Postgres`_ and `SQLite`_ databases in Nim.
|
||||||
|
## It supports a simple, opinionated model mapper to generate SQL queries based
|
||||||
|
## on Nim objects. It also includes a simple connection pooling implementation.
|
||||||
|
##
|
||||||
|
## Fiber ORM is not intended to be a 100% all-cases-covered ORM that handles
|
||||||
|
## every potential data access pattern one might wish to implement. It is best
|
||||||
|
## thought of as a collection of common SQL generation patterns. It is intended
|
||||||
|
## to cover 90% of the common queries and functions one might write when
|
||||||
|
## implementing an SQL-based access layer. It is expected that there may be a
|
||||||
|
## few more complicated queries that need to be implemented to handle specific
|
||||||
|
## access patterns.
|
||||||
|
##
|
||||||
|
## The simple mapping pattern provided by Fiber ORM also works well on top of
|
||||||
|
## databases that encapsulate data access logic in SQL with, for example,
|
||||||
|
## views.
|
||||||
|
##
|
||||||
|
## .. _Postgres: https://nim-lang.org/docs/db_postgres.html
|
||||||
|
## .. _SQLite: https://nim-lang.org/docs/db_sqlite.html
|
||||||
|
##
|
||||||
|
## Basic Usage
|
||||||
|
## ===========
|
||||||
|
##
|
||||||
|
## Consider a simple TODO list application that keeps track of TODO items as
|
||||||
|
## well as time logged against those items.
|
||||||
|
##
|
||||||
|
## Example DB Schema
|
||||||
|
## -----------------
|
||||||
|
##
|
||||||
|
## You might have a schema such as:
|
||||||
|
##
|
||||||
|
## .. code-block:: SQL
|
||||||
|
## create extension if not exists "pgcrypto";
|
||||||
|
##
|
||||||
|
## create table todo_items columns (
|
||||||
|
## id uuid not null primary key default gen_random_uuid(),
|
||||||
|
## owner varchar not null,
|
||||||
|
## summary varchar not null,
|
||||||
|
## details varchar default null,
|
||||||
|
## priority integer not null default 0,
|
||||||
|
## related_todo_item_ids uuid[] not null default '{}'
|
||||||
|
## );
|
||||||
|
##
|
||||||
|
## create table time_entries columns (
|
||||||
|
## id uuid not null primary key default gen_random_uuid(),
|
||||||
|
## todo_item_id uuid not null references todo_items (id) on delete cascade,
|
||||||
|
## start timestamp with timezone not null default current_timestamp,
|
||||||
|
## stop timestamp with timezone default null,
|
||||||
|
## );
|
||||||
|
##
|
||||||
|
## Example Model Definitions
|
||||||
|
## -------------------------
|
||||||
|
##
|
||||||
|
## Models may be defined as:
|
||||||
|
##
|
||||||
|
## .. code-block:: Nim
|
||||||
|
## # models.nim
|
||||||
|
## import std/options, std/times
|
||||||
|
## import uuids
|
||||||
|
##
|
||||||
|
## type
|
||||||
|
## TodoItem* = object
|
||||||
|
## id*: UUID
|
||||||
|
## owner*: string
|
||||||
|
## summary*: string
|
||||||
|
## details*: Option[string]
|
||||||
|
## priority*: int
|
||||||
|
## relatedTodoItemIds*: seq[UUID]
|
||||||
|
##
|
||||||
|
## TimeEntry* = object
|
||||||
|
## id*: UUID
|
||||||
|
## todoItemId*: Option[UUID]
|
||||||
|
## start*: DateTime
|
||||||
|
## stop*: Option[DateTime]
|
||||||
|
##
|
||||||
|
## Example Fiber ORM Usage
|
||||||
|
## -----------------------
|
||||||
|
##
|
||||||
|
## Using Fiber ORM we can generate a data access layer with:
|
||||||
|
##
|
||||||
|
## .. code-block:: Nim
|
||||||
|
## # db.nim
|
||||||
|
## import std/db_postgres
|
||||||
|
## import fiber_orm
|
||||||
|
## import ./models.nim
|
||||||
|
##
|
||||||
|
## type TodoDB* = DbConnPool
|
||||||
|
##
|
||||||
|
## proc initDb*(connString: string): TodoDB =
|
||||||
|
## result = fiber_orm.initPool(
|
||||||
|
## connect = proc(): DbConn = open("", "", "", connString),
|
||||||
|
## poolSize = 20,
|
||||||
|
## hardCap = false)
|
||||||
|
##
|
||||||
|
##
|
||||||
|
## generateProcsForModels(TodoDB, [TodoItem, TimeEntry])
|
||||||
|
##
|
||||||
|
## generateLookup(TodoDB, TimeEntry, @["todoItemId"])
|
||||||
|
##
|
||||||
|
## This will generate the following procedures:
|
||||||
|
##
|
||||||
|
## .. code-block:: Nim
|
||||||
|
## proc getTodoItem*(db: TodoDB, id: UUID): TodoItem;
|
||||||
|
##
|
||||||
|
## proc createTodoItem*(db: TodoDB, rec: TodoItem): TodoItem;
|
||||||
|
## proc updateTodoItem*(db: TodoDB, rec: TodoItem): bool;
|
||||||
|
## proc createOrUpdateTodoItem*(db: TodoDB, rec: TodoItem): bool;
|
||||||
|
## proc deleteTodoItem*(db: TodoDB, rec: TodoItem): bool;
|
||||||
|
## proc deleteTodoItem*(db: TodoDB, id: UUID): bool;
|
||||||
|
##
|
||||||
|
## proc getAllTodoItems*(db: TodoDB,
|
||||||
|
## pagination = none[PaginationParams]()): seq[TodoItem];
|
||||||
|
##
|
||||||
|
## proc findTodoItemsWhere*(db: TodoDB, whereClause: string,
|
||||||
|
## values: varargs[string, dbFormat], pagination = none[PaginationParams]()
|
||||||
|
## ): seq[TodoItem];
|
||||||
|
##
|
||||||
|
## proc getTimeEntry*(db: TodoDB, id: UUID): TimeEntry;
|
||||||
|
## proc createTimeEntry*(db: TodoDB, rec: TimeEntry): TimeEntry;
|
||||||
|
## proc updateTimeEntry*(db: TodoDB, rec: TimeEntry): bool;
|
||||||
|
## proc deleteTimeEntry*(db: TodoDB, rec: TimeEntry): bool;
|
||||||
|
## proc deleteTimeEntry*(db: TodoDB, id: UUID): bool;
|
||||||
|
##
|
||||||
|
## proc getAllTimeEntries*(db: TodoDB,
|
||||||
|
## pagination = none[PaginationParams]()): seq[TimeEntry];
|
||||||
|
##
|
||||||
|
## proc findTimeEntriesWhere*(db: TodoDB, whereClause: string,
|
||||||
|
## values: varargs[string, dbFormat], pagination = none[PaginationParams]()
|
||||||
|
## ): seq[TimeEntry];
|
||||||
|
##
|
||||||
|
## proc findTimeEntriesByTodoItemId(db: TodoDB, todoItemId: UUID,
|
||||||
|
## pagination = none[PaginationParams]()): seq[TimeEntry];
|
||||||
|
##
|
||||||
|
## Object-Relational Modeling
|
||||||
|
## ==========================
|
||||||
|
##
|
||||||
|
## Model Class
|
||||||
|
## -----------
|
||||||
|
##
|
||||||
|
## Fiber ORM uses simple Nim `object`s and `ref object`s as model classes.
|
||||||
|
## Fiber ORM expects there to be one table for each model class.
|
||||||
|
##
|
||||||
|
## Name Mapping
|
||||||
|
## ````````````
|
||||||
|
## Fiber ORM uses `snake_case` for database identifiers (column names, table
|
||||||
|
## names, etc.) and `camelCase` for Nim identifiers. We automatically convert
|
||||||
|
## model names to and from table names (`TodoItem` <-> `todo_items`), as well
|
||||||
|
## as column names (`userId` <-> `user_id`).
|
||||||
|
##
|
||||||
|
## Notice that table names are automatically pluralized from model class names.
|
||||||
|
## In the above example, you have:
|
||||||
|
##
|
||||||
|
## =========== ================
|
||||||
|
## Model Class Table Name
|
||||||
|
## =========== ================
|
||||||
|
## TodoItem todo_items
|
||||||
|
## TimeEntry time_entries
|
||||||
|
## =========== ================
|
||||||
|
##
|
||||||
|
## Because Nim is style-insensitive, you can generall refer to model classes
|
||||||
|
## and fields using `snake_case`, `camelCase`, or `PascalCase` in your code and
|
||||||
|
## expect Fiber ORM to be able to map the names to DB identifier names properly
|
||||||
|
## (though FiberORM will always use `camelCase` internally).
|
||||||
|
##
|
||||||
|
## See the `identNameToDb`_, `dbNameToIdent`_, `tableName`_ and `dbFormat`_
|
||||||
|
## procedures in the `fiber_orm/util`_ module for details.
|
||||||
|
##
|
||||||
|
## .. _identNameToDb: fiber_orm/util.html#identNameToDb,string
|
||||||
|
## .. _dbNameToIdent: fiber_orm/util.html#dbNameToIdent,string
|
||||||
|
## .. _tableName: fiber_orm/util.html#tableName,type
|
||||||
|
## .. _dbFormat: fiber_orm/util.html#dbFormat,DateTime
|
||||||
|
## .. _util: fiber_orm/util.html
|
||||||
|
##
|
||||||
|
## ID Field
|
||||||
|
## ````````
|
||||||
|
##
|
||||||
|
## Fiber ORM expects every model class to have a field named `id`, with a
|
||||||
|
## corresponding `id` column in the model table. This field must be either a
|
||||||
|
## `string`, `integer`, or `UUID`_.
|
||||||
|
##
|
||||||
|
## When creating a new record the `id` field will be omitted if it is empty
|
||||||
|
## (`Option.isNone`_, `UUID.isZero`_, value of `0`, or only whitespace). This
|
||||||
|
## is intended to allow for cases like the example where the database may
|
||||||
|
## generate an ID when a new record is inserted. If a non-zero value is
|
||||||
|
## provided, the create call will include the `id` field in the `INSERT` query.
|
||||||
|
##
|
||||||
|
## For example, to allow the database to create the id:
|
||||||
|
##
|
||||||
|
## .. code-block:: Nim
|
||||||
|
## let item = TodoItem(
|
||||||
|
## owner: "John Mann",
|
||||||
|
## summary: "Create a grocery list.",
|
||||||
|
## details: none[string](),
|
||||||
|
## priority: 0,
|
||||||
|
## relatedTodoItemIds: @[])
|
||||||
|
##
|
||||||
|
## let itemWithId = db.createTodoItem(item)
|
||||||
|
## echo $itemWithId.id # generated in the database
|
||||||
|
##
|
||||||
|
## And to create it in code:
|
||||||
|
##
|
||||||
|
## .. code-block:: Nim
|
||||||
|
## import uuids
|
||||||
|
##
|
||||||
|
## let item = TodoItem(
|
||||||
|
## id: genUUID(),
|
||||||
|
## owner: "John Mann",
|
||||||
|
## summary: "Create a grocery list.",
|
||||||
|
## details: none[string](),
|
||||||
|
## priority: 0,
|
||||||
|
## relatedTodoItemIds: @[])
|
||||||
|
##
|
||||||
|
## let itemInDb = db.createTodoItem(item)
|
||||||
|
## echo $itemInDb.id # will be the same as what was provided
|
||||||
|
##
|
||||||
|
## .. _Option.isNone: https://nim-lang.org/docs/options.html#isNone,Option[T]
|
||||||
|
## .. _UUID.isZero: https://github.com/pragmagic/uuids/blob/8cb8720b567c6bcb261bd1c0f7491bdb5209ad06/uuids.nim#L72
|
||||||
|
##
|
||||||
|
## Supported Data Types
|
||||||
|
## --------------------
|
||||||
|
##
|
||||||
|
## The following Nim data types are supported by Fiber ORM:
|
||||||
|
##
|
||||||
|
## =============== ====================== =================
|
||||||
|
## Nim Type Postgres Type SQLite Type
|
||||||
|
## =============== ====================== =================
|
||||||
|
## `string` `varchar`_
|
||||||
|
## `int` `integer`_
|
||||||
|
## `float` `double`_
|
||||||
|
## `bool` `boolean`_
|
||||||
|
## `DateTime`_ `timestamp`_
|
||||||
|
## `seq[]` `array`_
|
||||||
|
## `UUID`_ `uuid (pg)`_
|
||||||
|
## `Option`_ *allows* `NULL` [#f1]_
|
||||||
|
## `JsonNode`_ `jsonb`_
|
||||||
|
## =============== ====================== =================
|
||||||
|
##
|
||||||
|
## .. [#f1] Note that this implies that all `NULL`-able fields should be typed
|
||||||
|
## as optional using `Option[fieldType]`. Conversely, any fields with
|
||||||
|
## non-optional types should also be constrained to be `NOT NULL` in
|
||||||
|
## the database schema.
|
||||||
|
##
|
||||||
|
## .. _DateTime: https://nim-lang.org/docs/times.html#DateTime
|
||||||
|
## .. _UUID: https://github.com/pragmagic/uuids
|
||||||
|
## .. _Option: https://nim-lang.org/docs/options.html#Option
|
||||||
|
## .. _JsonNode: https://nim-lang.org/docs/json.html#JsonNode
|
||||||
|
##
|
||||||
|
## .. _varchar: https://www.postgresql.org/docs/current/datatype-character.html
|
||||||
|
## .. _integer: https://www.postgresql.org/docs/current/datatype-numeric.html#DATATYPE-INT
|
||||||
|
## .. _double: https://www.postgresql.org/docs/current/datatype-numeric.html#DATATYPE-FLOAT
|
||||||
|
## .. _boolean: https://www.postgresql.org/docs/current/datatype-boolean.html
|
||||||
|
## .. _timestamp: https://www.postgresql.org/docs/current/datatype-datetime.html
|
||||||
|
## .. _array: https://www.postgresql.org/docs/current/arrays.html
|
||||||
|
## .. _uuid (pg): https://www.postgresql.org/docs/current/datatype-uuid.html
|
||||||
|
## .. _jsonb: https://www.postgresql.org/docs/current/datatype-json.html
|
||||||
|
##
|
||||||
|
## Database Object
|
||||||
|
## ===============
|
||||||
|
##
|
||||||
|
## Many of the Fiber ORM macros expect a database object type to be passed.
|
||||||
|
## In the example above the `pool.DbConnPool`_ object is used as database
|
||||||
|
## object type (aliased as `TodoDB`). This is the intended usage pattern, but
|
||||||
|
## anything can be passed as the database object type so long as there is a
|
||||||
|
## defined `withConnection` template that provides a `conn: DbConn` object
|
||||||
|
## to the provided statement body.
|
||||||
|
##
|
||||||
|
## For example, a valid database object implementation that opens a new
|
||||||
|
## connection for every request might look like this:
|
||||||
|
##
|
||||||
|
## .. code-block:: Nim
|
||||||
|
## import db_connector/db_postgres
|
||||||
|
##
|
||||||
|
## type TodoDB* = object
|
||||||
|
## connString: string
|
||||||
|
##
|
||||||
|
## template withConnection*(db: TodoDB, stmt: untyped): untyped =
|
||||||
|
## block:
|
||||||
|
## let conn = open("", "", "", db.connString)
|
||||||
|
## try: stmt
|
||||||
|
## finally: close(conn)
|
||||||
|
##
|
||||||
|
## .. _pool.DbConnPool: fiber_orm/pool.html#DbConnPool
|
||||||
|
##
|
||||||
|
import std/[json, macros, options, sequtils, strutils]
|
||||||
|
import db_connector/db_common
|
||||||
|
import namespaced_logging, uuids
|
||||||
|
|
||||||
|
from std/unicode import capitalize
|
||||||
|
|
||||||
|
import ./fiber_orm/db_common as fiber_db_common
|
||||||
|
import ./fiber_orm/pool
|
||||||
import ./fiber_orm/util
|
import ./fiber_orm/util
|
||||||
|
|
||||||
type NotFoundError* = object of CatchableError
|
export pool, util
|
||||||
|
|
||||||
|
type
|
||||||
|
PagedRecords*[T] = object
|
||||||
|
pagination*: Option[PaginationParams]
|
||||||
|
records*: seq[T]
|
||||||
|
totalRecords*: int
|
||||||
|
|
||||||
|
DbUpdateError* = object of CatchableError ##\
|
||||||
|
## Error types raised when a DB modification fails.
|
||||||
|
|
||||||
|
NotFoundError* = object of CatchableError ##\
|
||||||
|
## Error type raised when no record matches a given ID
|
||||||
|
|
||||||
|
var logService {.threadvar.}: Option[LogService]
|
||||||
|
var logger {.threadvar.}: Option[Logger]
|
||||||
|
|
||||||
|
proc logQuery*(methodName: string, sqlStmt: string, args: openArray[(string, string)] = []) =
|
||||||
|
# namespaced_logging would do this check for us, but we don't want to even
|
||||||
|
# build the log object if we're not actually logging
|
||||||
|
if logService.isNone: return
|
||||||
|
if logger.isNone: logger = logService.getLogger("fiber_orm/query")
|
||||||
|
var log = %*{ "method": methodName, "sql": sqlStmt }
|
||||||
|
for (k, v) in args: log[k] = %v
|
||||||
|
logger.debug(log)
|
||||||
|
|
||||||
|
proc enableDbLogging*(svc: LogService) =
|
||||||
|
logService = some(svc)
|
||||||
|
|
||||||
proc newMutateClauses(): MutateClauses =
|
proc newMutateClauses(): MutateClauses =
|
||||||
return MutateClauses(
|
return MutateClauses(
|
||||||
@ -12,100 +329,269 @@ proc newMutateClauses(): MutateClauses =
|
|||||||
placeholders: @[],
|
placeholders: @[],
|
||||||
values: @[])
|
values: @[])
|
||||||
|
|
||||||
proc createRecord*[T](db: DbConn, rec: T): T =
|
proc createRecord*[D: DbConnType, T](db: D, rec: T): T =
|
||||||
|
## Create a new record. `rec` is expected to be a `model class`_. The `id`
|
||||||
|
## field is only set if it is non-empty (see `ID Field`_ for details).
|
||||||
|
##
|
||||||
|
## Returns the newly created record.
|
||||||
|
##
|
||||||
|
## .. _model class: #objectminusrelational-modeling-model-class
|
||||||
|
## .. _ID Field: #model-class-id-field
|
||||||
|
|
||||||
var mc = newMutateClauses()
|
var mc = newMutateClauses()
|
||||||
populateMutateClauses(rec, true, mc)
|
populateMutateClauses(rec, true, mc)
|
||||||
|
|
||||||
# Confusingly, getRow allows inserts and updates. We use it to get back the ID
|
let sqlStmt =
|
||||||
# we want from the row.
|
|
||||||
let newRow = db.getRow(sql(
|
|
||||||
"INSERT INTO " & tableName(rec) &
|
"INSERT INTO " & tableName(rec) &
|
||||||
" (" & mc.columns.join(",") & ") " &
|
" (" & mc.columns.join(",") & ") " &
|
||||||
" VALUES (" & mc.placeholders.join(",") & ") " &
|
" VALUES (" & mc.placeholders.join(",") & ") " &
|
||||||
" RETURNING *"), mc.values)
|
" RETURNING " & columnNamesForModel(rec).join(",")
|
||||||
|
|
||||||
|
logQuery("createRecord", sqlStmt)
|
||||||
|
let newRow = db.getRow(sql(sqlStmt), mc.values)
|
||||||
|
|
||||||
result = rowToModel(T, newRow)
|
result = rowToModel(T, newRow)
|
||||||
|
|
||||||
proc updateRecord*[T](db: DbConn, rec: T): bool =
|
proc updateRecord*[D: DbConnType, T](db: D, rec: T): bool =
|
||||||
|
## Update a record by id. `rec` is expected to be a `model class`_.
|
||||||
var mc = newMutateClauses()
|
var mc = newMutateClauses()
|
||||||
populateMutateClauses(rec, false, mc)
|
populateMutateClauses(rec, false, mc)
|
||||||
|
|
||||||
let setClause = zip(mc.columns, mc.placeholders).mapIt(it.a & " = " & it.b).join(",")
|
let setClause = zip(mc.columns, mc.placeholders).mapIt(it[0] & " = " & it[1]).join(",")
|
||||||
let numRowsUpdated = db.execAffectedRows(sql(
|
let sqlStmt =
|
||||||
"UPDATE " & tableName(rec) &
|
"UPDATE " & tableName(rec) &
|
||||||
" SET " & setClause &
|
" SET " & setClause &
|
||||||
" WHERE id = ? "), mc.values.concat(@[$rec.id]))
|
" WHERE id = ? "
|
||||||
|
|
||||||
|
logQuery("updateRecord", sqlStmt, [("id", $rec.id)])
|
||||||
|
let numRowsUpdated = db.execAffectedRows(sql(sqlStmt), mc.values.concat(@[$rec.id]))
|
||||||
|
|
||||||
return numRowsUpdated > 0;
|
return numRowsUpdated > 0;
|
||||||
|
|
||||||
template deleteRecord*(db: DbConn, modelType: type, id: typed): untyped =
|
proc createOrUpdateRecord*[D: DbConnType, T](db: D, rec: T): T =
|
||||||
db.tryExec(sql("DELETE FROM " & tableName(modelType) & " WHERE id = ?"), $id)
|
## Create or update a record. `rec` is expected to be a `model class`_. If
|
||||||
|
## the `id` field is unset, or if there is no existing record with the given
|
||||||
|
## id, a new record is inserted. Otherwise, the existing record is updated.
|
||||||
|
##
|
||||||
|
## Note that this does not perform partial updates, all fields are updated.
|
||||||
|
|
||||||
proc deleteRecord*[T](db: DbConn, rec: T): bool =
|
let findRecordStmt = "SELECT id FROM " & tableName(rec) & " WHERE id = ?"
|
||||||
return db.tryExec(sql("DELETE FROM " & tableName(rec) & " WHERE id = ?"), $rec.id)
|
logQuery("createOrUpdateRecord", findRecordStmt, [("id", $rec.id)])
|
||||||
|
let rows = db.getAllRows(sql(findRecordStmt), [$rec.id])
|
||||||
|
|
||||||
template getRecord*(db: DbConn, modelType: type, id: typed): untyped =
|
if rows.len == 0: result = createRecord(db, rec)
|
||||||
let row = db.getRow(sql(
|
else:
|
||||||
|
result = rec
|
||||||
|
if not updateRecord(db, rec):
|
||||||
|
raise newException(DbUpdateError,
|
||||||
|
"unable to update " & modelName(rec) & " for id " & $rec.id)
|
||||||
|
|
||||||
|
template deleteRecord*[D: DbConnType](db: D, modelType: type, id: typed): untyped =
|
||||||
|
## Delete a record by id.
|
||||||
|
let sqlStmt = "DELETE FROM " & tableName(modelType) & " WHERE id = ?"
|
||||||
|
logQuery("deleteRecord", sqlStmt, [("id", $id)])
|
||||||
|
db.tryExec(sql(sqlStmt), $id)
|
||||||
|
|
||||||
|
proc deleteRecord*[D: DbConnType, T](db: D, rec: T): bool =
|
||||||
|
## Delete a record by `id`_.
|
||||||
|
##
|
||||||
|
## .. _id: #model-class-id-field
|
||||||
|
let sqlStmt = "DELETE FROM " & tableName(rec) & " WHERE id = ?"
|
||||||
|
logQuery("deleteRecord", sqlStmt, [("id", $rec.id)])
|
||||||
|
return db.tryExec(sql(sqlStmt), $rec.id)
|
||||||
|
|
||||||
|
template getRecord*[D: DbConnType](db: D, modelType: type, id: typed): untyped =
|
||||||
|
## Fetch a record by id.
|
||||||
|
let sqlStmt =
|
||||||
"SELECT " & columnNamesForModel(modelType).join(",") &
|
"SELECT " & columnNamesForModel(modelType).join(",") &
|
||||||
" FROM " & tableName(modelType) &
|
" FROM " & tableName(modelType) &
|
||||||
" WHERE id = ?"), @[$id])
|
" WHERE id = ?"
|
||||||
|
|
||||||
if row.allIt(it.len == 0):
|
logQuery("getRecord", sqlStmt, [("id", $id)])
|
||||||
raise newException(NotFoundError, "no record for id " & $id)
|
let row = db.getRow(sql(sqlStmt), @[$id])
|
||||||
|
|
||||||
|
if allIt(row, it.len == 0):
|
||||||
|
raise newException(NotFoundError, "no " & modelName(modelType) & " record for id " & $id)
|
||||||
|
|
||||||
rowToModel(modelType, row)
|
rowToModel(modelType, row)
|
||||||
|
|
||||||
template findRecordsWhere*(db: DbConn, modelType: type, whereClause: string, values: varargs[string, dbFormat]): untyped =
|
template findRecordsWhere*[D: DbConnType](
|
||||||
db.getAllRows(sql(
|
db: D,
|
||||||
|
modelType: type,
|
||||||
|
whereClause: string,
|
||||||
|
values: varargs[string, dbFormat],
|
||||||
|
page: Option[PaginationParams]): untyped =
|
||||||
|
## Find all records matching a given `WHERE` clause. The number of elements in
|
||||||
|
## the `values` array must match the number of placeholders (`?`) in the
|
||||||
|
## provided `WHERE` clause.
|
||||||
|
var fetchStmt =
|
||||||
"SELECT " & columnNamesForModel(modelType).join(",") &
|
"SELECT " & columnNamesForModel(modelType).join(",") &
|
||||||
" FROM " & tableName(modelType) &
|
" FROM " & tableName(modelType) &
|
||||||
" WHERE " & whereClause), values)
|
" WHERE " & whereClause
|
||||||
.mapIt(rowToModel(modelType, it))
|
|
||||||
|
|
||||||
template getAllRecords*(db: DbConn, modelType: type): untyped =
|
var countStmt =
|
||||||
db.getAllRows(sql(
|
"SELECT COUNT(*) FROM " & tableName(modelType) &
|
||||||
|
" WHERE " & whereClause
|
||||||
|
|
||||||
|
if page.isSome: fetchStmt &= getPagingClause(page.get)
|
||||||
|
|
||||||
|
logQuery("findRecordsWhere", fetchStmt, [("values", values.join(", "))])
|
||||||
|
let records = db.getAllRows(sql(fetchStmt), values).mapIt(rowToModel(modelType, it))
|
||||||
|
|
||||||
|
PagedRecords[modelType](
|
||||||
|
pagination: page,
|
||||||
|
records: records,
|
||||||
|
totalRecords:
|
||||||
|
if page.isNone: records.len
|
||||||
|
else: db.getRow(sql(countStmt), values)[0].parseInt)
|
||||||
|
|
||||||
|
template getAllRecords*[D: DbConnType](
|
||||||
|
db: D,
|
||||||
|
modelType: type,
|
||||||
|
page: Option[PaginationParams]): untyped =
|
||||||
|
## Fetch all records of the given type.
|
||||||
|
var fetchStmt =
|
||||||
"SELECT " & columnNamesForModel(modelType).join(",") &
|
"SELECT " & columnNamesForModel(modelType).join(",") &
|
||||||
" FROM " & tableName(modelType)))
|
" FROM " & tableName(modelType)
|
||||||
.mapIt(rowToModel(modelType, it))
|
|
||||||
|
|
||||||
template findRecordsBy*(db: DbConn, modelType: type, lookups: seq[tuple[field: string, value: string]]): untyped =
|
var countStmt = "SELECT COUNT(*) FROM " & tableName(modelType)
|
||||||
db.getAllRows(sql(
|
|
||||||
|
if page.isSome: fetchStmt &= getPagingClause(page.get)
|
||||||
|
|
||||||
|
logQuery("getAllRecords", fetchStmt)
|
||||||
|
let records = db.getAllRows(sql(fetchStmt)).mapIt(rowToModel(modelType, it))
|
||||||
|
|
||||||
|
PagedRecords[modelType](
|
||||||
|
pagination: page,
|
||||||
|
records: records,
|
||||||
|
totalRecords:
|
||||||
|
if page.isNone: records.len
|
||||||
|
else: db.getRow(sql(countStmt))[0].parseInt)
|
||||||
|
|
||||||
|
|
||||||
|
template findRecordsBy*[D: DbConnType](
|
||||||
|
db: D,
|
||||||
|
modelType: type,
|
||||||
|
lookups: seq[tuple[field: string, value: string]],
|
||||||
|
page: Option[PaginationParams]): untyped =
|
||||||
|
## Find all records matching the provided lookup values.
|
||||||
|
let whereClause = lookups.mapIt(it.field & " = ?").join(" AND ")
|
||||||
|
let values = lookups.mapIt(it.value)
|
||||||
|
|
||||||
|
var fetchStmt =
|
||||||
"SELECT " & columnNamesForModel(modelType).join(",") &
|
"SELECT " & columnNamesForModel(modelType).join(",") &
|
||||||
" FROM " & tableName(modelType) &
|
" FROM " & tableName(modelType) &
|
||||||
" WHERE " & lookups.mapIt(it.field & " = ?").join(" AND ")),
|
" WHERE " & whereClause
|
||||||
lookups.mapIt(it.value))
|
|
||||||
.mapIt(rowToModel(modelType, it))
|
|
||||||
|
|
||||||
macro generateProcsForModels*(modelTypes: openarray[type]): untyped =
|
var countStmt =
|
||||||
|
"SELECT COUNT(*) FROM " & tableName(modelType) &
|
||||||
|
" WHERE " & whereClause
|
||||||
|
|
||||||
|
if page.isSome: fetchStmt &= getPagingClause(page.get)
|
||||||
|
|
||||||
|
logQuery("findRecordsBy", fetchStmt, [("values", values.join(", "))])
|
||||||
|
let records = db.getAllRows(sql(fetchStmt), values).mapIt(rowToModel(modelType, it))
|
||||||
|
|
||||||
|
PagedRecords[modelType](
|
||||||
|
pagination: page,
|
||||||
|
records: records,
|
||||||
|
totalRecords:
|
||||||
|
if page.isNone: records.len
|
||||||
|
else: db.getRow(sql(countStmt), values)[0].parseInt)
|
||||||
|
|
||||||
|
|
||||||
|
macro generateProcsForModels*(dbType: type, modelTypes: openarray[type]): untyped =
|
||||||
|
## Generate all standard access procedures for the given model types. For a
|
||||||
|
## `model class`_ named `TodoItem`, this will generate the following
|
||||||
|
## procedures:
|
||||||
|
##
|
||||||
|
## .. code-block:: Nim
|
||||||
|
## proc getTodoItem*(db: TodoDB, id: idType): TodoItem;
|
||||||
|
## proc getAllTodoItems*(db: TodoDB): TodoItem;
|
||||||
|
## proc createTodoItem*(db: TodoDB, rec: TodoItem): TodoItem;
|
||||||
|
## proc deleteTodoItem*(db: TodoDB, rec: TodoItem): bool;
|
||||||
|
## proc deleteTodoItem*(db: TodoDB, id: idType): bool;
|
||||||
|
## proc updateTodoItem*(db: TodoDB, rec: TodoItem): bool;
|
||||||
|
## proc createOrUpdateTodoItem*(db: TodoDB, rec: TodoItem): bool;
|
||||||
|
##
|
||||||
|
## proc findTodoItemsWhere*(
|
||||||
|
## db: TodoDB, whereClause: string, values: varargs[string]): TodoItem;
|
||||||
|
##
|
||||||
|
## `dbType` is expected to be some type that has a defined `withConnection`
|
||||||
|
## procedure (see `Database Object`_ for details).
|
||||||
|
##
|
||||||
|
## .. _Database Object: #database-object
|
||||||
result = newStmtList()
|
result = newStmtList()
|
||||||
|
|
||||||
for t in modelTypes:
|
for t in modelTypes:
|
||||||
|
if t.getType[1].typeKind == ntyRef:
|
||||||
|
raise newException(ValueError,
|
||||||
|
"fiber_orm model object must be objects, not refs")
|
||||||
|
|
||||||
let modelName = $(t.getType[1])
|
let modelName = $(t.getType[1])
|
||||||
let getName = ident("get" & modelName)
|
let getName = ident("get" & modelName)
|
||||||
let getAllName = ident("getAll" & modelName & "s")
|
let getIfExistsName = ident("get" & modelName & "IfItExists")
|
||||||
let findWhereName = ident("find" & modelName & "sWhere")
|
let getAllName = ident("getAll" & pluralize(modelName))
|
||||||
|
let findWhereName = ident("find" & pluralize(modelName) & "Where")
|
||||||
let createName = ident("create" & modelName)
|
let createName = ident("create" & modelName)
|
||||||
let updateName = ident("update" & modelName)
|
let updateName = ident("update" & modelName)
|
||||||
|
let createOrUpdateName = ident("createOrUpdate" & modelName)
|
||||||
let deleteName = ident("delete" & modelName)
|
let deleteName = ident("delete" & modelName)
|
||||||
let idType = typeOfColumn(t, "id")
|
let idType = typeOfColumn(t, "id")
|
||||||
result.add quote do:
|
result.add quote do:
|
||||||
proc `getName`*(db: PMApiDb, id: `idType`): `t` = getRecord(db.conn, `t`, id)
|
proc `getName`*(db: `dbType`, id: `idType`): `t` =
|
||||||
proc `getAllName`*(db: PMApiDb): seq[`t`] = getAllRecords(db.conn, `t`)
|
db.withConnection conn: result = getRecord(conn, `t`, id)
|
||||||
proc `findWhereName`*(db: PMApiDb, whereClause: string, values: varargs[string, dbFormat]): seq[`t`] =
|
|
||||||
return findRecordsWhere(db.conn, `t`, whereClause, values)
|
|
||||||
proc `createName`*(db: PMApiDb, rec: `t`): `t` = createRecord(db.conn, rec)
|
|
||||||
proc `updateName`*(db: PMApiDb, rec: `t`): bool = updateRecord(db.conn, rec)
|
|
||||||
proc `deleteName`*(db: PMApiDb, rec: `t`): bool = deleteRecord(db.conn, rec)
|
|
||||||
proc `deleteName`*(db: PMApiDb, id: `idType`): bool = deleteRecord(db.conn, `t`, id)
|
|
||||||
|
|
||||||
macro generateLookup*(modelType: type, fields: seq[string]): untyped =
|
proc `getIfExistsName`*(db: `dbType`, id: `idType`): Option[`t`] =
|
||||||
|
db.withConnection conn:
|
||||||
|
try: result = some(getRecord(conn, `t`, id))
|
||||||
|
except NotFoundError: result = none[`t`]()
|
||||||
|
|
||||||
|
proc `getAllName`*(db: `dbType`, pagination = none[PaginationParams]()): PagedRecords[`t`] =
|
||||||
|
db.withConnection conn: result = getAllRecords(conn, `t`, pagination)
|
||||||
|
|
||||||
|
proc `findWhereName`*(
|
||||||
|
db: `dbType`,
|
||||||
|
whereClause: string,
|
||||||
|
values: varargs[string, dbFormat],
|
||||||
|
pagination = none[PaginationParams]()): PagedRecords[`t`] =
|
||||||
|
db.withConnection conn:
|
||||||
|
result = findRecordsWhere(conn, `t`, whereClause, values, pagination)
|
||||||
|
|
||||||
|
proc `createName`*(db: `dbType`, rec: `t`): `t` =
|
||||||
|
db.withConnection conn: result = createRecord(conn, rec)
|
||||||
|
|
||||||
|
proc `updateName`*(db: `dbType`, rec: `t`): bool =
|
||||||
|
db.withConnection conn: result = updateRecord(conn, rec)
|
||||||
|
|
||||||
|
proc `createOrUpdateName`*(db: `dbType`, rec: `t`): `t` =
|
||||||
|
db.inTransaction: result = createOrUpdateRecord(conn, rec)
|
||||||
|
|
||||||
|
proc `deleteName`*(db: `dbType`, rec: `t`): bool =
|
||||||
|
db.withConnection conn: result = deleteRecord(conn, rec)
|
||||||
|
|
||||||
|
proc `deleteName`*(db: `dbType`, id: `idType`): bool =
|
||||||
|
db.withConnection conn: result = deleteRecord(conn, `t`, id)
|
||||||
|
|
||||||
|
macro generateLookup*(dbType: type, modelType: type, fields: seq[string]): untyped =
|
||||||
|
## Create a lookup procedure for a given set of field names. For example,
|
||||||
|
## given the TODO database demostrated above,
|
||||||
|
##
|
||||||
|
## .. code-block:: Nim
|
||||||
|
## generateLookup(TodoDB, TodoItem, ["owner", "priority"])
|
||||||
|
##
|
||||||
|
## will generate the following procedure:
|
||||||
|
##
|
||||||
|
## .. code-block:: Nim
|
||||||
|
## proc findTodoItemsByOwnerAndPriority*(db: SampleDB,
|
||||||
|
## owner: string, priority: int): seq[TodoItem]
|
||||||
let fieldNames = fields[1].mapIt($it)
|
let fieldNames = fields[1].mapIt($it)
|
||||||
let procName = ident("find" & $modelType.getType[1] & "sBy" & fieldNames.mapIt(it.capitalize).join("And"))
|
let procName = ident("find" & pluralize($modelType.getType[1]) & "By" & fieldNames.mapIt(it.capitalize).join("And"))
|
||||||
|
|
||||||
# Create proc skeleton
|
# Create proc skeleton
|
||||||
result = quote do:
|
result = quote do:
|
||||||
proc `procName`*(db: PMApiDb): seq[`modelType`] =
|
proc `procName`*(db: `dbType`): PagedRecords[`modelType`] =
|
||||||
return findRecordsBy(db.conn, `modelType`)
|
db.withConnection conn: result = findRecordsBy(conn, `modelType`)
|
||||||
|
|
||||||
var callParams = quote do: @[]
|
var callParams = quote do: @[]
|
||||||
|
|
||||||
@ -115,12 +601,27 @@ macro generateLookup*(modelType: type, fields: seq[string]): untyped =
|
|||||||
paramTuple.add(newColonExpr(ident("field"), newLit(identNameToDb(n))))
|
paramTuple.add(newColonExpr(ident("field"), newLit(identNameToDb(n))))
|
||||||
paramTuple.add(newColonExpr(ident("value"), ident(n)))
|
paramTuple.add(newColonExpr(ident("value"), ident(n)))
|
||||||
|
|
||||||
|
# Add the parameter to the outer call (the generated proc)
|
||||||
|
# result[3] is ProcDef -> [3]: FormalParams
|
||||||
result[3].add(newIdentDefs(ident(n), ident("string")))
|
result[3].add(newIdentDefs(ident(n), ident("string")))
|
||||||
|
|
||||||
|
# Build up the AST for the inner procedure call
|
||||||
callParams[1].add(paramTuple)
|
callParams[1].add(paramTuple)
|
||||||
|
|
||||||
result[6][0][0].add(callParams)
|
# Add the optional pagination parameters to the generated proc definition
|
||||||
|
result[3].add(newIdentDefs(
|
||||||
|
ident("pagination"), newEmptyNode(),
|
||||||
|
quote do: none[PaginationParams]()))
|
||||||
|
|
||||||
macro generateProcsForFieldLookups*(modelsAndFields: openarray[tuple[t: type, fields: seq[string]]]): untyped =
|
# Add the call params to the inner procedure call
|
||||||
|
# result[6][0][1][0][1] is
|
||||||
|
# ProcDef -> [6]: StmtList (body) -> [0]: Command ->
|
||||||
|
# [2]: StmtList (withConnection body) -> [0]: Asgn (result =) ->
|
||||||
|
# [1]: Call (inner findRecords invocation)
|
||||||
|
result[6][0][2][0][1].add(callParams)
|
||||||
|
result[6][0][2][0][1].add(quote do: pagination)
|
||||||
|
|
||||||
|
macro generateProcsForFieldLookups*(dbType: type, modelsAndFields: openarray[tuple[t: type, fields: seq[string]]]): untyped =
|
||||||
result = newStmtList()
|
result = newStmtList()
|
||||||
|
|
||||||
for i in modelsAndFields:
|
for i in modelsAndFields:
|
||||||
@ -131,20 +632,65 @@ macro generateProcsForFieldLookups*(modelsAndFields: openarray[tuple[t: type, fi
|
|||||||
|
|
||||||
# Create proc skeleton
|
# Create proc skeleton
|
||||||
let procDefAST = quote do:
|
let procDefAST = quote do:
|
||||||
proc `procName`*(db: PMApiDb): seq[`modelType`] =
|
proc `procName`*(db: `dbType`): PagedRecords[`modelType`] =
|
||||||
return findRecordsBy(db.conn, `modelType`)
|
db.withConnection conn: result = findRecordsBy(conn, `modelType`)
|
||||||
|
|
||||||
var callParams = quote do: @[]
|
var callParams = quote do: @[]
|
||||||
|
|
||||||
# Add dynamic parameters for the proc definition and inner proc call
|
# Add dynamic parameters for the proc definition and inner proc call
|
||||||
for n in fieldNames:
|
for n in fieldNames:
|
||||||
let paramTuple = newNimNode(nnkPar)
|
let paramTuple = newNimNode(nnkPar)
|
||||||
paramTuple.add(newColonExpr(ident("field"), newLit(n)))
|
paramTuple.add(newColonExpr(ident("field"), newLit(identNameToDb(n))))
|
||||||
paramTuple.add(newColonExpr(ident("value"), ident(n)))
|
paramTuple.add(newColonExpr(ident("value"), ident(n)))
|
||||||
|
|
||||||
procDefAST[3].add(newIdentDefs(ident(n), ident("string")))
|
procDefAST[3].add(newIdentDefs(ident(n), ident("string")))
|
||||||
callParams[1].add(paramTuple)
|
callParams[1].add(paramTuple)
|
||||||
|
|
||||||
procDefAST[6][0][0].add(callParams)
|
# Add the optional pagination parameters to the generated proc definition
|
||||||
|
procDefAST[3].add(newIdentDefs(
|
||||||
|
ident("pagination"), newEmptyNode(),
|
||||||
|
quote do: none[PaginationParams]()))
|
||||||
|
|
||||||
|
procDefAST[6][0][1][0][1].add(callParams)
|
||||||
|
procDefAST[6][0][1][0][1].add(quote do: pagination)
|
||||||
|
|
||||||
result.add procDefAST
|
result.add procDefAST
|
||||||
|
|
||||||
|
proc initPool*[D: DbConnType](
|
||||||
|
connect: proc(): D,
|
||||||
|
poolSize = 10,
|
||||||
|
hardCap = false,
|
||||||
|
healthCheckQuery = "SELECT 'true' AS alive"): DbConnPool[D] =
|
||||||
|
|
||||||
|
## Initialize a new DbConnPool. See the `initDb` procedure in the `Example
|
||||||
|
## Fiber ORM Usage`_ for an example
|
||||||
|
##
|
||||||
|
## * `connect` must be a factory which creates a new `DbConn`.
|
||||||
|
## * `poolSize` sets the desired capacity of the connection pool.
|
||||||
|
## * `hardCap` defaults to `false`.
|
||||||
|
## When `false`, the pool can grow beyond the configured capacity, but will
|
||||||
|
## release connections down to the its capacity (no less than `poolSize`).
|
||||||
|
##
|
||||||
|
## When `true` the pool will not create more than its configured capacity.
|
||||||
|
## It a connection is requested, none are free, and the pool is at
|
||||||
|
## capacity, this will result in an Error being raised.
|
||||||
|
## * `healthCheckQuery` should be a simple and fast SQL query that the pool
|
||||||
|
## can use to test the liveliness of pooled connections.
|
||||||
|
##
|
||||||
|
## .. _Example Fiber ORM Usage: #basic-usage-example-fiber-orm-usage
|
||||||
|
|
||||||
|
initDbConnPool(DbConnPoolConfig[D](
|
||||||
|
connect: connect,
|
||||||
|
poolSize: poolSize,
|
||||||
|
hardCap: hardCap,
|
||||||
|
healthCheckQuery: healthCheckQuery))
|
||||||
|
|
||||||
|
template inTransaction*(db, body: untyped) =
|
||||||
|
db.withConnection conn:
|
||||||
|
conn.exec(sql"BEGIN TRANSACTION")
|
||||||
|
try:
|
||||||
|
body
|
||||||
|
conn.exec(sql"COMMIT")
|
||||||
|
except:
|
||||||
|
conn.exec(sql"ROLLBACK")
|
||||||
|
raise getCurrentException()
|
||||||
|
3
src/fiber_orm/db_common.nim
Normal file
3
src/fiber_orm/db_common.nim
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
import db_connector/[db_postgres, db_sqlite]
|
||||||
|
|
||||||
|
type DbConnType* = db_postgres.DbConn or db_sqlite.DbConn
|
114
src/fiber_orm/pool.nim
Normal file
114
src/fiber_orm/pool.nim
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
# Fiber ORM
|
||||||
|
#
|
||||||
|
# Copyright 2019 Jonathan Bernard <jonathan@jdbernard.com>
|
||||||
|
|
||||||
|
## Simple database connection pooling implementation compatible with Fiber ORM.
|
||||||
|
|
||||||
|
import std/[sequtils, strutils, sugar]
|
||||||
|
import db_connector/db_common
|
||||||
|
|
||||||
|
from db_connector/db_sqlite import getRow, close
|
||||||
|
from db_connector/db_postgres import getRow, close
|
||||||
|
|
||||||
|
import ./db_common as fiber_db_common
|
||||||
|
|
||||||
|
type
|
||||||
|
DbConnPoolConfig*[D: DbConnType] = object
|
||||||
|
connect*: () -> D ## Factory procedure to create a new DBConn
|
||||||
|
poolSize*: int ## The pool capacity.
|
||||||
|
|
||||||
|
hardCap*: bool ## Is the pool capacity a hard cap?
|
||||||
|
##
|
||||||
|
## When `false`, the pool can grow beyond the
|
||||||
|
## configured capacity, but will release connections
|
||||||
|
## down to the its capacity (no less than `poolSize`).
|
||||||
|
##
|
||||||
|
## When `true` the pool will not create more than its
|
||||||
|
## configured capacity. It a connection is requested,
|
||||||
|
## none are free, and the pool is at capacity, this
|
||||||
|
## will result in an Error being raised.
|
||||||
|
|
||||||
|
healthCheckQuery*: string ## Should be a simple and fast SQL query that the
|
||||||
|
## pool can use to test the liveliness of pooled
|
||||||
|
## connections.
|
||||||
|
|
||||||
|
PooledDbConn[D: DbConnType] = ref object
|
||||||
|
conn: D
|
||||||
|
id: int
|
||||||
|
free: bool
|
||||||
|
|
||||||
|
DbConnPool*[D: DbConnType] = ref object
|
||||||
|
## Database connection pool
|
||||||
|
conns: seq[PooledDbConn[D]]
|
||||||
|
cfg: DbConnPoolConfig[D]
|
||||||
|
lastId: int
|
||||||
|
|
||||||
|
proc initDbConnPool*[D: DbConnType](cfg: DbConnPoolConfig[D]): DbConnPool[D] =
|
||||||
|
result = DbConnPool[D](
|
||||||
|
conns: @[],
|
||||||
|
cfg: cfg)
|
||||||
|
|
||||||
|
proc newConn[D: DbConnType](pool: DbConnPool[D]): PooledDbConn[D] =
|
||||||
|
pool.lastId += 1
|
||||||
|
{.gcsafe.}:
|
||||||
|
let conn = pool.cfg.connect()
|
||||||
|
result = PooledDbConn[D](
|
||||||
|
conn: conn,
|
||||||
|
id: pool.lastId,
|
||||||
|
free: true)
|
||||||
|
pool.conns.add(result)
|
||||||
|
|
||||||
|
proc maintain[D: DbConnType](pool: DbConnPool[D]): void =
|
||||||
|
pool.conns.keepIf(proc (pc: PooledDbConn[D]): bool =
|
||||||
|
if not pc.free: return true
|
||||||
|
|
||||||
|
try:
|
||||||
|
discard getRow(pc.conn, sql(pool.cfg.healthCheckQuery), [])
|
||||||
|
return true
|
||||||
|
except:
|
||||||
|
try: pc.conn.close() # try to close the connection
|
||||||
|
except: discard ""
|
||||||
|
return false
|
||||||
|
)
|
||||||
|
|
||||||
|
let freeConns = pool.conns.filterIt(it.free)
|
||||||
|
if pool.conns.len > pool.cfg.poolSize and freeConns.len > 0:
|
||||||
|
let numToCull = min(freeConns.len, pool.conns.len - pool.cfg.poolSize)
|
||||||
|
|
||||||
|
if numToCull > 0:
|
||||||
|
let toCull = freeConns[0..numToCull]
|
||||||
|
pool.conns.keepIf((pc) => toCull.allIt(it.id != pc.id))
|
||||||
|
for culled in toCull:
|
||||||
|
try: culled.conn.close()
|
||||||
|
except: discard ""
|
||||||
|
|
||||||
|
proc take*[D: DbConnType](pool: DbConnPool[D]): tuple[id: int, conn: D] =
|
||||||
|
## Request a connection from the pool. Returns a DbConn if the pool has free
|
||||||
|
## connections, or if it has the capacity to create a new connection. If the
|
||||||
|
## pool is configured with a hard capacity limit and is out of free
|
||||||
|
## connections, this will raise an Error.
|
||||||
|
##
|
||||||
|
## Connections taken must be returned via `release` when the caller is
|
||||||
|
## finished using them in order for them to be released back to the pool.
|
||||||
|
pool.maintain
|
||||||
|
let freeConns = pool.conns.filterIt(it.free)
|
||||||
|
|
||||||
|
let reserved =
|
||||||
|
if freeConns.len > 0: freeConns[0]
|
||||||
|
else: pool.newConn()
|
||||||
|
|
||||||
|
reserved.free = false
|
||||||
|
return (id: reserved.id, conn: reserved.conn)
|
||||||
|
|
||||||
|
proc release*[D: DbConnType](pool: DbConnPool[D], connId: int): void =
|
||||||
|
## Release a connection back to the pool.
|
||||||
|
let foundConn = pool.conns.filterIt(it.id == connId)
|
||||||
|
if foundConn.len > 0: foundConn[0].free = true
|
||||||
|
|
||||||
|
template withConnection*[D: DbConnType](pool: DbConnPool[D], conn, stmt: untyped): untyped =
|
||||||
|
## Convenience template to provide a connection from the pool for use in a
|
||||||
|
## statement block, automatically releasing that connnection when done.
|
||||||
|
block:
|
||||||
|
let (connId, conn) = take(pool)
|
||||||
|
try: stmt
|
||||||
|
finally: release(pool, connId)
|
@ -1,34 +1,71 @@
|
|||||||
import json, macros, options, sequtils, strutils, times, timeutils, unicode,
|
# Fiber ORM
|
||||||
uuids
|
#
|
||||||
|
# Copyright 2019 Jonathan Bernard <jonathan@jdbernard.com>
|
||||||
|
|
||||||
const UNDERSCORE_RUNE = "_".toRunes[0]
|
## Utility methods used internally by Fiber ORM.
|
||||||
const PG_TIMESTAMP_FORMATS = [
|
import std/[json, macros, options, sequtils, strutils, times, unicode]
|
||||||
"yyyy-MM-dd HH:mm:sszz",
|
import uuids
|
||||||
"yyyy-MM-dd HH:mm:ss'.'fzz",
|
|
||||||
"yyyy-MM-dd HH:mm:ss'.'ffzz",
|
import std/nre except toSeq
|
||||||
"yyyy-MM-dd HH:mm:ss'.'fffzz"
|
|
||||||
]
|
|
||||||
|
|
||||||
type
|
type
|
||||||
|
PaginationParams* = object
|
||||||
|
pageSize*: int
|
||||||
|
offset*: int
|
||||||
|
orderBy*: Option[seq[string]]
|
||||||
|
|
||||||
MutateClauses* = object
|
MutateClauses* = object
|
||||||
|
## Data structure to hold information about the clauses that should be
|
||||||
|
## added to a query. How these clauses are used will depend on the query.
|
||||||
|
## This common data structure provides the information needed to create
|
||||||
|
## WHERE clauses, UPDATE clauses, etc.
|
||||||
columns*: seq[string]
|
columns*: seq[string]
|
||||||
placeholders*: seq[string]
|
placeholders*: seq[string]
|
||||||
values*: seq[string]
|
values*: seq[string]
|
||||||
|
|
||||||
|
const ISO_8601_FORMATS = @[
|
||||||
|
"yyyy-MM-dd'T'HH:mm:ssz",
|
||||||
|
"yyyy-MM-dd'T'HH:mm:sszzz",
|
||||||
|
"yyyy-MM-dd'T'HH:mm:ss'.'fffzzz",
|
||||||
|
"yyyy-MM-dd'T'HH:mm:ss'.'ffffzzz",
|
||||||
|
"yyyy-MM-dd HH:mm:ssz",
|
||||||
|
"yyyy-MM-dd HH:mm:sszzz",
|
||||||
|
"yyyy-MM-dd HH:mm:ss'.'fffzzz",
|
||||||
|
"yyyy-MM-dd HH:mm:ss'.'ffffzzz"
|
||||||
|
]
|
||||||
|
|
||||||
|
proc parseIso8601(val: string): DateTime =
|
||||||
|
var errString = ""
|
||||||
|
for df in ISO_8601_FORMATS:
|
||||||
|
try: return val.parse(df)
|
||||||
|
except: errString &= "\n" & getCurrentExceptionMsg()
|
||||||
|
raise newException(Exception, "Could not parse date. Tried:" & errString)
|
||||||
|
|
||||||
|
proc formatIso8601(d: DateTime): string =
|
||||||
|
return d.format(ISO_8601_FORMATS[2])
|
||||||
|
|
||||||
|
|
||||||
# TODO: more complete implementation
|
# TODO: more complete implementation
|
||||||
# see https://github.com/blakeembrey/pluralize
|
# see https://github.com/blakeembrey/pluralize
|
||||||
proc pluralize(name: string): string =
|
proc pluralize*(name: string): string =
|
||||||
|
## Return the plural form of the given name.
|
||||||
if name[^2..^1] == "ey": return name[0..^3] & "ies"
|
if name[^2..^1] == "ey": return name[0..^3] & "ies"
|
||||||
if name[^1] == 'y': return name[0..^2] & "ies"
|
if name[^1] == 'y': return name[0..^2] & "ies"
|
||||||
return name & "s"
|
return name & "s"
|
||||||
|
|
||||||
macro modelName*(model: object): string =
|
macro modelName*(model: object): string =
|
||||||
|
## For a given concrete record object, return the name of the `model class`_
|
||||||
return newStrLitNode($model.getTypeInst)
|
return newStrLitNode($model.getTypeInst)
|
||||||
|
|
||||||
macro modelName*(modelType: type): string =
|
macro modelName*(modelType: type): string =
|
||||||
|
## Get the name of a given `model class`_
|
||||||
return newStrLitNode($modelType.getType[1])
|
return newStrLitNode($modelType.getType[1])
|
||||||
|
|
||||||
proc identNameToDb*(name: string): string =
|
proc identNameToDb*(name: string): string =
|
||||||
|
## Map a Nim identifier name to a DB name. See the `rules for name mapping`_
|
||||||
|
##
|
||||||
|
## TODO link above
|
||||||
|
const UNDERSCORE_RUNE = "_".toRunes[0]
|
||||||
let nameInRunes = name.toRunes
|
let nameInRunes = name.toRunes
|
||||||
var prev: Rune
|
var prev: Rune
|
||||||
var resultRunes = newSeq[Rune]()
|
var resultRunes = newSeq[Rune]()
|
||||||
@ -46,35 +83,82 @@ proc identNameToDb*(name: string): string =
|
|||||||
return $resultRunes
|
return $resultRunes
|
||||||
|
|
||||||
proc dbNameToIdent*(name: string): string =
|
proc dbNameToIdent*(name: string): string =
|
||||||
|
## Map a DB name to a Nim identifier name. See the `rules for name mapping`_
|
||||||
let parts = name.split("_")
|
let parts = name.split("_")
|
||||||
return @[parts[0]].concat(parts[1..^1].mapIt(capitalize(it))).join("")
|
return @[parts[0]].concat(parts[1..^1].mapIt(capitalize(it))).join("")
|
||||||
|
|
||||||
proc tableName*(modelType: type): string =
|
proc tableName*(modelType: type): string =
|
||||||
|
## Get the `table name`_ for a given `model class`_
|
||||||
return pluralize(modelName(modelType).identNameToDb)
|
return pluralize(modelName(modelType).identNameToDb)
|
||||||
|
|
||||||
proc tableName*[T](rec: T): string =
|
proc tableName*[T](rec: T): string =
|
||||||
|
## Get the `table name`_ for a given record.
|
||||||
return pluralize(modelName(rec).identNameToDb)
|
return pluralize(modelName(rec).identNameToDb)
|
||||||
|
|
||||||
proc dbFormat*(s: string): string = return s
|
proc dbFormat*(s: string): string =
|
||||||
|
## Format a string for inclusion in a SQL Query.
|
||||||
|
return s
|
||||||
|
|
||||||
proc dbFormat*(dt: DateTime): string = return dt.formatIso8601
|
proc dbFormat*(dt: DateTime): string =
|
||||||
|
## Format a DateTime for inclusion in a SQL Query.
|
||||||
|
return dt.formatIso8601
|
||||||
|
|
||||||
proc dbFormat*[T](list: seq[T]): string =
|
proc dbFormat*[T](list: seq[T]): string =
|
||||||
|
## Format a `seq` for inclusion in a SQL Query.
|
||||||
return "{" & list.mapIt(dbFormat(it)).join(",") & "}"
|
return "{" & list.mapIt(dbFormat(it)).join(",") & "}"
|
||||||
|
|
||||||
proc dbFormat*[T](item: T): string = return $item
|
proc dbFormat*[T](item: T): string =
|
||||||
|
## For all other types, fall back on a defined `$` function to create a
|
||||||
|
## string version of the value we can include in an SQL query.
|
||||||
|
return $item
|
||||||
|
|
||||||
type DbArrayParseState = enum
|
type DbArrayParseState = enum
|
||||||
expectStart, inQuote, inVal, expectEnd
|
expectStart, inQuote, inVal, expectEnd
|
||||||
|
|
||||||
proc parsePGDatetime*(val: string): DateTime =
|
proc parsePGDatetime*(val: string): DateTime =
|
||||||
|
## Parse a Postgres datetime value into a Nim DateTime object.
|
||||||
|
|
||||||
|
const PG_TIMESTAMP_FORMATS = [
|
||||||
|
"yyyy-MM-dd HH:mm:ss",
|
||||||
|
"yyyy-MM-dd'T'HH:mm:ss",
|
||||||
|
"yyyy-MM-dd HH:mm:sszz",
|
||||||
|
"yyyy-MM-dd'T'HH:mm:sszz",
|
||||||
|
"yyyy-MM-dd HH:mm:ss'.'fff",
|
||||||
|
"yyyy-MM-dd'T'HH:mm:ss'.'fff",
|
||||||
|
"yyyy-MM-dd HH:mm:ss'.'fffzz",
|
||||||
|
"yyyy-MM-dd'T'HH:mm:ss'.'fffzz",
|
||||||
|
"yyyy-MM-dd HH:mm:ss'.'fffzzz",
|
||||||
|
"yyyy-MM-dd'T'HH:mm:ss'.'fffzzz",
|
||||||
|
]
|
||||||
|
|
||||||
|
var correctedVal = val;
|
||||||
|
|
||||||
|
# The Nim `times#format` function only recognizes 3-digit millisecond values
|
||||||
|
# but PostgreSQL will sometimes send 1-2 digits, truncating any trailing 0's,
|
||||||
|
# or sometimes provide more than three digits of preceision in the millisecond value leading
|
||||||
|
# to values like `2020-01-01 16:42.3+00` or `2025-01-06 00:56:00.9007+00`.
|
||||||
|
# This cannot currently be parsed by the standard times format as it expects
|
||||||
|
# exactly three digits for millisecond values. So we have to detect this and
|
||||||
|
# coerce the millisecond value to exactly 3 digits.
|
||||||
|
let PG_PARTIAL_FORMAT_REGEX = re"(\d{4}-\d{2}-\d{2}( |'T')\d{2}:\d{2}:\d{2}\.)(\d+)(\S+)?"
|
||||||
|
let match = val.match(PG_PARTIAL_FORMAT_REGEX)
|
||||||
|
|
||||||
|
if match.isSome:
|
||||||
|
let c = match.get.captures
|
||||||
|
if c.toSeq.len == 2: correctedVal = c[0] & alignLeft(c[2], 3, '0')[0..2]
|
||||||
|
else: correctedVal = c[0] & alignLeft(c[2], 3, '0')[0..2] & c[3]
|
||||||
|
|
||||||
var errStr = ""
|
var errStr = ""
|
||||||
|
|
||||||
|
# Try to parse directly using known format strings.
|
||||||
for df in PG_TIMESTAMP_FORMATS:
|
for df in PG_TIMESTAMP_FORMATS:
|
||||||
try: return val.parse(df)
|
try: return correctedVal.parse(df)
|
||||||
except: errStr &= "\n" & getCurrentExceptionMsg()
|
except: errStr &= "\n\t" & getCurrentExceptionMsg()
|
||||||
raise newException(ValueError, "Cannot parse PG date. Tried:" & errStr)
|
|
||||||
|
raise newException(ValueError, "Cannot parse PG date '" & correctedVal & "'. Tried:" & errStr)
|
||||||
|
|
||||||
proc parseDbArray*(val: string): seq[string] =
|
proc parseDbArray*(val: string): seq[string] =
|
||||||
|
## Parse a Postgres array column into a Nim seq[string]
|
||||||
result = newSeq[string]()
|
result = newSeq[string]()
|
||||||
|
|
||||||
var parseState = DbArrayParseState.expectStart
|
var parseState = DbArrayParseState.expectStart
|
||||||
@ -132,26 +216,46 @@ proc parseDbArray*(val: string): seq[string] =
|
|||||||
if not (parseState == inQuote) and curStr.len > 0:
|
if not (parseState == inQuote) and curStr.len > 0:
|
||||||
result.add(curStr)
|
result.add(curStr)
|
||||||
|
|
||||||
proc createParseStmt*(t, value: NimNode): NimNode =
|
func createParseStmt*(t, value: NimNode): NimNode =
|
||||||
|
## Utility method to create the Nim cod required to parse a value coming from
|
||||||
|
## the a database query. This is used by functions like `rowToModel` to parse
|
||||||
|
## the dataabase columns into the Nim object fields.
|
||||||
|
|
||||||
#echo "Creating parse statment for ", t.treeRepr
|
|
||||||
if t.typeKind == ntyObject:
|
if t.typeKind == ntyObject:
|
||||||
|
|
||||||
if t.getType == UUID.getType:
|
if t.getTypeInst == Option.getType:
|
||||||
result = quote do: parseUUID(`value`)
|
var innerType = t.getTypeImpl[2][0] # start at the first RecList
|
||||||
|
# If the value is a non-pointer type, there is another inner RecList
|
||||||
|
if innerType.kind == nnkRecList: innerType = innerType[0]
|
||||||
|
innerType = innerType[1] # now we can take the field type from the first symbol
|
||||||
|
|
||||||
elif t.getType == DateTime.getType:
|
|
||||||
result = quote do: parsePGDatetime(`value`)
|
|
||||||
|
|
||||||
elif t.getTypeInst == Option.getType:
|
|
||||||
let innerType = t.getTypeImpl[2][0][0][1]
|
|
||||||
let parseStmt = createParseStmt(innerType, value)
|
let parseStmt = createParseStmt(innerType, value)
|
||||||
result = quote do:
|
result = quote do:
|
||||||
if `value`.len == 0: none[`innerType`]()
|
if `value`.len == 0: none[`innerType`]()
|
||||||
else: some(`parseStmt`)
|
else: some(`parseStmt`)
|
||||||
|
|
||||||
|
elif t.getType == UUID.getType:
|
||||||
|
result = quote do: parseUUID(`value`)
|
||||||
|
|
||||||
|
elif t.getType == DateTime.getType:
|
||||||
|
result = quote do: parsePGDatetime(`value`)
|
||||||
|
|
||||||
else: error "Unknown value object type: " & $t.getTypeInst
|
else: error "Unknown value object type: " & $t.getTypeInst
|
||||||
|
|
||||||
|
elif t.typeKind == ntyGenericInst:
|
||||||
|
|
||||||
|
if t.kind == nnkBracketExpr and
|
||||||
|
t.len > 0 and
|
||||||
|
t[0] == Option.getType:
|
||||||
|
|
||||||
|
var innerType = t.getTypeInst[1]
|
||||||
|
let parseStmt = createParseStmt(innerType, value)
|
||||||
|
result = quote do:
|
||||||
|
if `value`.len == 0: none[`innerType`]()
|
||||||
|
else: some(`parseStmt`)
|
||||||
|
|
||||||
|
else: error "Unknown generic instance type: " & $t.getTypeInst
|
||||||
|
|
||||||
elif t.typeKind == ntyRef:
|
elif t.typeKind == ntyRef:
|
||||||
|
|
||||||
if $t.getTypeInst == "JsonNode":
|
if $t.getTypeInst == "JsonNode":
|
||||||
@ -173,33 +277,89 @@ proc createParseStmt*(t, value: NimNode): NimNode =
|
|||||||
elif t.typeKind == ntyInt:
|
elif t.typeKind == ntyInt:
|
||||||
result = quote do: parseInt(`value`)
|
result = quote do: parseInt(`value`)
|
||||||
|
|
||||||
|
elif t.typeKind == ntyFloat:
|
||||||
|
result = quote do: parseFloat(`value`)
|
||||||
|
|
||||||
elif t.typeKind == ntyBool:
|
elif t.typeKind == ntyBool:
|
||||||
result = quote do: "true".startsWith(`value`.toLower)
|
result = quote do: "true".startsWith(`value`.toLower)
|
||||||
|
|
||||||
|
elif t.typeKind == ntyEnum:
|
||||||
|
let innerType = t.getTypeInst
|
||||||
|
result = quote do: parseEnum[`innerType`](`value`)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
error "Unknown value type: " & $t.typeKind
|
error "Unknown value type: " & $t.typeKind
|
||||||
|
|
||||||
template walkFieldDefs*(t: NimNode, body: untyped) =
|
func fields(t: NimNode): seq[tuple[fieldIdent: NimNode, fieldType: NimNode]] =
|
||||||
let tTypeImpl = t.getTypeImpl
|
#[
|
||||||
|
debugEcho "T: " & t.treeRepr
|
||||||
|
debugEcho "T.kind: " & $t.kind
|
||||||
|
debugEcho "T.typeKind: " & $t.typeKind
|
||||||
|
debugEcho "T.GET_TYPE[1]: " & t.getType[1].treeRepr
|
||||||
|
debugEcho "T.GET_TYPE[1].kind: " & $t.getType[1].kind
|
||||||
|
debugEcho "T.GET_TYPE[1].typeKind: " & $t.getType[1].typeKind
|
||||||
|
|
||||||
var nodeToItr: NimNode
|
debugEcho "T.GET_TYPE: " & t.getType.treeRepr
|
||||||
if tTypeImpl.typeKind == ntyObject: nodeToItr = tTypeImpl[2]
|
debugEcho "T.GET_TYPE[1].GET_TYPE: " & t.getType[1].getType.treeRepr
|
||||||
elif tTypeImpl.typeKind == ntyTypeDesc: nodeToItr = tTypeImpl.getType[1].getType[2]
|
]#
|
||||||
else: error $t & " is not an object or type desc (it's a " & $tTypeImpl.typeKind & ")."
|
|
||||||
|
|
||||||
for fieldDef {.inject.} in nodeToItr.children:
|
# Get the object type AST, with base object (if present) and record list.
|
||||||
|
var objDefAst: NimNode
|
||||||
|
if t.typeKind == ntyObject: objDefAst = t.getType
|
||||||
|
elif t.typeKind == ntyTypeDesc:
|
||||||
|
# In this case we have a type AST that is like:
|
||||||
|
# BracketExpr
|
||||||
|
# Sym "typeDesc"
|
||||||
|
# Sym "ModelType"
|
||||||
|
objDefAst = t.
|
||||||
|
getType[1]. # get the Sym "ModelType"
|
||||||
|
getType # get the object definition type
|
||||||
|
|
||||||
|
if objDefAst.kind != nnkObjectTy:
|
||||||
|
error ("unable to enumerate the fields for model type '$#', " &
|
||||||
|
"tried to resolve the type of the provided symbol to an object " &
|
||||||
|
"definition (nnkObjectTy) but got a '$#'.\pAST:\p$#") % [
|
||||||
|
$t, $objDefAst.kind, objDefAst.treeRepr ]
|
||||||
|
else:
|
||||||
|
error ("unable to enumerate the fields for model type '$#', " &
|
||||||
|
"expected a symbol with type ntyTypeDesc but got a '$#'.\pAST:\p$#") % [
|
||||||
|
$t, $t.typeKind, t.treeRepr ]
|
||||||
|
|
||||||
|
# At this point objDefAst should look something like:
|
||||||
|
# ObjectTy
|
||||||
|
# Empty
|
||||||
|
# Sym "BaseObject"" | Empty
|
||||||
|
# RecList
|
||||||
|
# Sym "field1"
|
||||||
|
# Sym "field2"
|
||||||
|
# ...
|
||||||
|
|
||||||
|
if objDefAst[1].kind == nnkSym:
|
||||||
|
# We have a base class symbol, let's recurse and try and resolve the fields
|
||||||
|
# for the base class
|
||||||
|
for fieldDef in objDefAst[1].fields: result.add(fieldDef)
|
||||||
|
|
||||||
|
for fieldDef in objDefAst[2].children:
|
||||||
|
# objDefAst[2] is a RecList of
|
||||||
# ignore AST nodes that are not field definitions
|
# ignore AST nodes that are not field definitions
|
||||||
if fieldDef.kind == nnkIdentDefs:
|
if fieldDef.kind == nnkIdentDefs: result.add((fieldDef[0], fieldDef[1]))
|
||||||
let fieldIdent {.inject.} = fieldDef[0]
|
elif fieldDef.kind == nnkSym: result.add((fieldDef, fieldDef.getTypeInst))
|
||||||
let fieldType {.inject.} = fieldDef[1]
|
else: error "unknown object field definition AST: $#" % $fieldDef.kind
|
||||||
body
|
|
||||||
|
|
||||||
elif fieldDef.kind == nnkSym:
|
template walkFieldDefs*(t: NimNode, body: untyped) =
|
||||||
let fieldIdent {.inject.} = fieldDef
|
## Iterate over every field of the given Nim object, yielding and defining
|
||||||
let fieldType {.inject.} = fieldDef.getType
|
## `fieldIdent` and `fieldType`, the name of the field as a Nim Ident node
|
||||||
body
|
## and the type of the field as a Nim Type node respectively.
|
||||||
|
for (fieldIdent {.inject.}, fieldType {.inject.}) in t.fields: body
|
||||||
|
|
||||||
|
#[ TODO: replace walkFieldDefs with things like this:
|
||||||
|
func columnNamesForModel*(modelType: typedesc): seq[string] =
|
||||||
|
modelType.fields.mapIt(identNameToDb($it[0]))
|
||||||
|
]#
|
||||||
|
|
||||||
macro columnNamesForModel*(modelType: typed): seq[string] =
|
macro columnNamesForModel*(modelType: typed): seq[string] =
|
||||||
|
## Return the column names corresponding to the the fields of the given
|
||||||
|
## `model class`_
|
||||||
var columnNames = newSeq[string]()
|
var columnNames = newSeq[string]()
|
||||||
|
|
||||||
modelType.walkFieldDefs:
|
modelType.walkFieldDefs:
|
||||||
@ -208,6 +368,8 @@ macro columnNamesForModel*(modelType: typed): seq[string] =
|
|||||||
result = newLit(columnNames)
|
result = newLit(columnNames)
|
||||||
|
|
||||||
macro rowToModel*(modelType: typed, row: seq[string]): untyped =
|
macro rowToModel*(modelType: typed, row: seq[string]): untyped =
|
||||||
|
## Return a new Nim model object of type `modelType` populated with the
|
||||||
|
## values returned in the given database `row`
|
||||||
|
|
||||||
# Create the object constructor AST node
|
# Create the object constructor AST node
|
||||||
result = newNimNode(nnkObjConstr).add(modelType)
|
result = newNimNode(nnkObjConstr).add(modelType)
|
||||||
@ -221,6 +383,7 @@ macro rowToModel*(modelType: typed, row: seq[string]): untyped =
|
|||||||
createParseStmt(fieldType, itemLookup)))
|
createParseStmt(fieldType, itemLookup)))
|
||||||
idx += 1
|
idx += 1
|
||||||
|
|
||||||
|
#[
|
||||||
macro listFields*(t: typed): untyped =
|
macro listFields*(t: typed): untyped =
|
||||||
var fields: seq[tuple[n: string, t: string]] = @[]
|
var fields: seq[tuple[n: string, t: string]] = @[]
|
||||||
t.walkFieldDefs:
|
t.walkFieldDefs:
|
||||||
@ -228,8 +391,10 @@ macro listFields*(t: typed): untyped =
|
|||||||
else: fields.add((n: $fieldIdent, t: $fieldType))
|
else: fields.add((n: $fieldIdent, t: $fieldType))
|
||||||
|
|
||||||
result = newLit(fields)
|
result = newLit(fields)
|
||||||
|
]#
|
||||||
|
|
||||||
proc typeOfColumn*(modelType: NimNode, colName: string): NimNode =
|
proc typeOfColumn*(modelType: NimNode, colName: string): NimNode =
|
||||||
|
## Given a model type and a column name, return the Nim type for that column.
|
||||||
modelType.walkFieldDefs:
|
modelType.walkFieldDefs:
|
||||||
if $fieldIdent != colName: continue
|
if $fieldIdent != colName: continue
|
||||||
|
|
||||||
@ -241,13 +406,18 @@ proc typeOfColumn*(modelType: NimNode, colName: string): NimNode =
|
|||||||
else: error "Unknown column type: " & $fieldType.getTypeInst
|
else: error "Unknown column type: " & $fieldType.getTypeInst
|
||||||
|
|
||||||
else: return fieldType
|
else: return fieldType
|
||||||
|
|
||||||
raise newException(Exception,
|
raise newException(Exception,
|
||||||
"model of type '" & $modelType & "' has no column named '" & colName & "'")
|
"model of type '" & $modelType & "' has no column named '" & colName & "'")
|
||||||
|
|
||||||
proc isZero(val: int): bool = return val == 0
|
proc isEmpty(val: int): bool = return val == 0
|
||||||
|
proc isEmpty(val: UUID): bool = return val.isZero
|
||||||
|
proc isEmpty(val: string): bool = return val.isEmptyOrWhitespace
|
||||||
|
proc isEmpty[T](val: Option[T]): bool = return val.isNone
|
||||||
|
|
||||||
macro populateMutateClauses*(t: typed, newRecord: bool, mc: var MutateClauses): untyped =
|
macro populateMutateClauses*(t: typed, newRecord: bool, mc: var MutateClauses): untyped =
|
||||||
|
## Given a record type, create the datastructure used to generate SQL clauses
|
||||||
|
## for the fields of this record type.
|
||||||
|
|
||||||
result = newStmtList()
|
result = newStmtList()
|
||||||
|
|
||||||
@ -257,23 +427,23 @@ macro populateMutateClauses*(t: typed, newRecord: bool, mc: var MutateClauses):
|
|||||||
# grab the field, it's string name, and it's type
|
# grab the field, it's string name, and it's type
|
||||||
let fieldName = $fieldIdent
|
let fieldName = $fieldIdent
|
||||||
|
|
||||||
# we do not update the ID, but we do check: if we're creating a new
|
# We only add clauses for the ID field if we're creating a new record and
|
||||||
# record, we should not have an existing ID
|
# the caller provided a value..
|
||||||
if fieldName == "id":
|
if fieldName == "id":
|
||||||
result.add quote do:
|
result.add quote do:
|
||||||
if `newRecord` and not `t`.id.isZero:
|
if `newRecord` and not `t`.id.isEmpty:
|
||||||
raise newException(
|
`mc`.columns.add(identNameToDb(`fieldName`))
|
||||||
AssertionError,
|
`mc`.placeholders.add("?")
|
||||||
"Trying to create a new record, but the record already has an ID (" & $(`t`.id) & ").")
|
`mc`.values.add(dbFormat(`t`.`fieldIdent`))
|
||||||
|
|
||||||
# if we're looking at an optional field, add logic to check for presence
|
# if we're looking at an optional field, add logic to check for presence
|
||||||
elif fieldType.kind == nnkBracketExpr and
|
elif fieldType.kind == nnkBracketExpr and
|
||||||
fieldType.len > 0 and
|
fieldType.len > 0 and
|
||||||
fieldType[0] == Option.getType:
|
fieldType[0] == Option.getType:
|
||||||
|
|
||||||
result.add quote do:
|
result.add quote do:
|
||||||
`mc`.columns.add(identNameToDb(`fieldName`))
|
`mc`.columns.add(identNameToDb(`fieldName`))
|
||||||
if `t`.`fieldIdent`.isSome:
|
if isSome(`t`.`fieldIdent`):
|
||||||
`mc`.placeholders.add("?")
|
`mc`.placeholders.add("?")
|
||||||
`mc`.values.add(dbFormat(`t`.`fieldIdent`.get))
|
`mc`.values.add(dbFormat(`t`.`fieldIdent`.get))
|
||||||
else:
|
else:
|
||||||
@ -285,3 +455,20 @@ macro populateMutateClauses*(t: typed, newRecord: bool, mc: var MutateClauses):
|
|||||||
`mc`.columns.add(identNameToDb(`fieldName`))
|
`mc`.columns.add(identNameToDb(`fieldName`))
|
||||||
`mc`.placeholders.add("?")
|
`mc`.placeholders.add("?")
|
||||||
`mc`.values.add(dbFormat(`t`.`fieldIdent`))
|
`mc`.values.add(dbFormat(`t`.`fieldIdent`))
|
||||||
|
|
||||||
|
|
||||||
|
proc getPagingClause*(page: PaginationParams): string =
|
||||||
|
## Given a `PaginationParams` object, return the SQL clause necessary to
|
||||||
|
## limit the number of records returned by a query.
|
||||||
|
result = ""
|
||||||
|
if page.orderBy.isSome:
|
||||||
|
let orderByClause = page.orderBy.get.map(identNameToDb).join(",")
|
||||||
|
result &= " ORDER BY " & orderByClause
|
||||||
|
else:
|
||||||
|
result &= " ORDER BY id"
|
||||||
|
|
||||||
|
result &= " LIMIT " & $page.pageSize & " OFFSET " & $page.offset
|
||||||
|
|
||||||
|
## .. _model class: ../fiber_orm.html#objectminusrelational-modeling-model-class
|
||||||
|
## .. _rules for name mapping: ../fiber_orm.html
|
||||||
|
## .. _table name: ../fiber_orm.html
|
||||||
|
Loading…
x
Reference in New Issue
Block a user