- Nim 2.x has moved the DB connectors outside the standard library to
the `db_connector` package.
- Refactor the pooling implementation and macro expectations to use the
`withConnection` name instead of `withConn`. This change allows a
caller to use a [waterpark](https://github.com/guzba/waterpark) pool
instance instead of the builtin pool instance. Waterpark provides
better support for multi-threaded environments. The builtin pooling
mechanism may be deprecated in favor of waterpark in the future.
- Add the `getModelIfItExists` generated proc to the list of standard
procs we generate. This is a flavour of `getModel` that returns an
`Option` instead of raising an exception when there is no model for
the given id.
- Change `PaginationParams#orderBy` to accept a `seq[string]` to allow
for sorting on multiple fields.
`createOrUpdateRecord` implements upsert: update an existing record if
it exists or create a new record if not. A new error `DbUpdateError` was
added to be raised when an existing record does exist but was not able
to be updated.
The first step in culling connections was to take a subset of the pool's
connections from index 0 to numToCull. This leads to an error if
numToCull is also zero.
The Nim [Row][nim-row] implementation only supports positional
identification of columns. In other words, there is nothing to tell us
which column is in which position. Because of this, we always create SQL
statements which explicitly name the columns we wish to receive so that
we know the order of columns and can rebuild models appropriately.
`createRule` wasn't doing this but naively using `RETURNING *`. This
still works as long as the field ordering in the Nim model class match
the default column ordering returned by the database, but confuses
columns otherwise. This fixes that by specifying explicitly the column
ordering as we do in other places.
[nim-row]: https://nim-lang.org/docs/db_postgres.html#Row
The previous implementation expected to work with a context object that
contained a field `conn` that represented a valid database connection.
However, this required the caller to manage the connection's lifecycle
(close, renew, etc.). Now we expect to receive a context object that
provides a `withConn` procedure or template that accepts a statement
block and provides a `conn` variable to that code block. For example:
createRecord(db: DbContext): Record =
# withConn must be defined for DbContext
db.withConn:
# conn must be injected into the statement block context
conn.exec(sql("INSERT INTO..."))
In addition, this change provides a connection pooling mechanism
(`DbConnPool`) as a default implementation for this hypothetical
DbContext. There is also a new function `initPool` that will create an
DbConnPool instance.
Callers of this library can modify their DbContext objects to extend
DbConnPool or simply be a type alias of DbConnPool.
Recognize versions of timestamps with 'T' as the date/time separator.
For example, compare:
'2021-08-01 23:14:00-05:00'
'2021-08-01T23:14:00-05:00'
This commit adds support for the second flavor (and it's variations).
The previous fix for PostgreSQL timestamp fields matched fields with and
without timezones, but did not properly parse values from fields that
included the timezone. Now we check for the presence of the timezone in
the date string and choose a format string to parse it correctly.
* Previously all ID types needed to have the `isZero` function defined.
This was named after the UUID.isZero function but does not describe
the general case. Non-numeric is types will not be "zero," they will
be "empty." Renamed to `isEmpty` and implemented basic versions of
this for `int`, `string`, and `UUID`.
* Previously newly created records were not allowed to have ids set.
Fiber required them to be set in the database and the caller to
retrieve the newly generated ID from the newly created record. This is
not really a decision that Fiber should make in a general case. There
are valid reasons for both possibilities (creating the id in the
application code vs. creating the id in the database layer). As a
more general-purpose solution Fiber now leaves this to the caller.
If the caller provides an id value, Fiber will include it in the
INSERT statement. If the id is unset, Fiber will not include it at
all, allowing it to be generated in the database.
The Option type has two forms depending on the type of the wrapped value
(see https://nim-lang.org/docs/options.html#Option). We only supported
one of these previously. This commit adds support for the other type as
well.
Additionally, this fixes a compile error that was introduced into the
use of `isSome` in the generated code after Nim 1.0.
PostgreSQL uses a format similar to IS8601 but allows values expressed
with tenths or hundreths of seconds rather than just milliseconds.
`2020-01-01 12:34:98.3+00` as opposed to `2020-01-01 12:34:98.300+00`,
for example. The `times` module in the Nim stdlib supports only
milliseconds with exactly three digits. To bridge this gap we detect the
two unsupported cases and pad the fractional seconds out to millisecond
precision.