update ActiveRecord documentation

This commit is contained in:
Günter Obiltschnig 2021-06-19 17:00:40 +02:00
parent 9a2711af57
commit 0ba235d401
3 changed files with 66 additions and 9 deletions

View File

@ -1,5 +1,5 @@
POCO C++ Libraries ActiveRecord Framework
POCO ActiveRecord User Guide
POCO ActiveRecord Framework
!!!Introduction
@ -9,9 +9,10 @@ to relieve developers from having to write lots of boilerplate database
query code for common operations like finding an object by ID, updating an object, deleting
an object or running paged queries. As its name implies, the framework follows
the well-known [[https://en.wikipedia.org/wiki/Active_record_pattern Active Record]]
architectural pattern. It's based on a code generator (named *Active Record Compiler*,
architectural pattern. It's based on a code generator (named <*ActiveRecord Compiler*>,
or <[arc]>) and uses a convention-over-configuration approach.
!!!Getting Started
The starting point for using the ActiveRecord framework is an XML file.
@ -21,9 +22,9 @@ generates corresponding header and source files defining and implementing
the respective C++ classes, as well as type handlers for the POCO Data
library.
Following is a first example for such an XML file. The file defines two
Following is an example for such an XML file. The file defines two
classes, an `Employee` class (mapped to a table named `employees`), and
a `Role` class (mapped to a table names `roles`).
a `Role` class (mapped to a table named `roles`).
<project namespace="Sample">
<class name="Employee" table="employees">
@ -46,6 +47,11 @@ There is a n:1 relationship between `Employee` and `Role` (each employee
has exactly one role). Furthermore, each employee can optionally have
a manager, which is again an `Employee`.
Properties named `id` are considered to be primary keys, unless a different
property has been designated the primary key (with the `key` attribute in
the `class` element). It's also possible to have objects without a primary key
or ID column (keyless active records).
The generated C++ classes will be in the `Sample` namespace, as specified
in the <[project]> element.
@ -53,7 +59,7 @@ The definitions in the XML file correspond to the database schema built
by the following <[CREATE TABLE]> statements:
CREATE TABLE employees (
id CHAR(36),
id CHAR(36) PRIMARY KEY,
name VARCHAR(64),
ssn VARCHAR(32),
role INTEGER,
@ -67,6 +73,9 @@ by the following <[CREATE TABLE]> statements:
);
----
If the database engine supports it, the `id` column of the `employees` table can be
an UUID as well.
Running the ActiveRecord Compiler with the above XML file (sample.xml) with the
following statement:
@ -85,8 +94,8 @@ will create the following files in the current working directory:
----
The generated classes are derived from the Poco::ActiveRecord::ActiveRecord class
template and have accessor methods for all properties, as well as methods
for creating, updating and deleting instances in the database.
template and have accessor methods for all properties defined in the XML file,
as well as methods for creating, updating and deleting instances in the database.
ActiveRecord objects are reference counted, and every generated class contains
a `Ptr` type alias for an appropriate Poco::AutoPtr<>.
@ -264,6 +273,10 @@ allows some additional flexibility.
const auto result = query.execute();
----
The lambda expression is passed a const reference to an ActiveRecord object and
must return a `bool`. If `true` is returned, the object is included in the result,
otherwise not.
!Relations
Relations (defined in the XML file as properties with a `references` attribute)
@ -284,7 +297,7 @@ In the following sample, the `role` property is set with the key value, whereas
pEmployee->create(pContext);
----
!Auto-increment Keys and Auto-generated UUIDs on Insert
!Auto-Increment Keys and Auto-Generated UUIDs on Insert
ActiveRecord supports auto-incrementing keys when inserting an ActiveRecord. T
o enable this feature, the `autoIncrementID` attribute in the `class` element needs
@ -297,7 +310,16 @@ mechanisms.
When inserting an ActiveRecord with an all-null UUID, a random UUID will be generated
before executing the `INSERT` statement.
!!!XML Reference
!Keyless Active Records
It is possible to define classes without an ID or primary key property. For these objects,
no `find()` method will be generated, and updating these objects is also not possible
(`update()` will throw a Poco::NotImplementedException).
Keyless ActiveRecord objects can be retrieved by executing a Poco::ActiveRecord::Query.
!!!Compiler XML Reference
!!Supported Data Types

View File

@ -28,6 +28,15 @@ namespace ActiveRecord {
template <typename ActRec>
class Query
/// A Query is used to retrieve ActiveRecord objects from a table.
///
/// As the name implies, Query supports selection of database rows
/// based on a WHERE clause (see where()). Furthermore, results can
/// be sorted (see orderBy()) and filtered based on a lambda expression
/// (see filter()).
///
/// Optional result paging is controlled by offest() and limit().
/// The total number of results is available via totalResults().
{
public:
explicit Query(Context::Ptr pContext):
@ -43,12 +52,20 @@ public:
Query& operator = (const Query&) = delete;
Query& where(const std::string& clause)
/// Specify a WHERE clause (without the WHERE keyword)
/// to select only rows matching the clause.
///
/// Placeholders (?) can be used in the clause. For each
/// placeholder, an actual value must be bound before
/// the query is executed (see bind()).
{
_select << " WHERE " << fixPlaceholders(clause);
return *this;
}
Query& orderBy(const std::string& order)
/// Specify a column name and optional direction (ASC, DESC)
/// to order the result by.
{
_select << " ORDER BY " << order;
return *this;
@ -56,24 +73,34 @@ public:
template <typename T>
Query& bind(const T& value)
/// Bind a value to a placeholder in the where clause.
{
_select, Poco::Data::Keywords::bind(value);
return *this;
}
Query& offset(std::size_t offset)
/// Specify the index or offset of the first row
/// to return for paging.
{
_offset = offset;
return *this;
}
Query& limit(std::size_t limit)
/// specify the maximum number of rows to return for paging.
{
_limit = limit;
return *this;
}
Query& filter(const std::function<bool(const ActRec&)>& fn)
/// Specify a lambda expression for filtering results.
///
/// The lamda takes a const reference to the ActiveRecord
/// (template argument) as parameter and must return a
/// bool. If the lambda returns true, the respective ActiveRecord
/// is included in the query result.
{
_filter = fn;
return *this;
@ -86,6 +113,8 @@ public:
}
std::vector<typename ActRec::Ptr> execute()
/// Execute the query and return a vector with the
/// results.
{
std::vector<typename ActRec::Ptr> result;
@ -115,11 +144,15 @@ public:
}
std::size_t totalResults() const
/// In case of a paged query, returns the total number of results
/// that would be returned without paging.
{
return _totalResults;
}
void reset()
/// Resets the query so that it can be executed again, with
/// potentially different parameters.
{
_offset = 0;
_limit = 0;

View File

@ -11,3 +11,5 @@ PageCompiler
PageCompiler/File2Page
MongoDB
Redis
ActiveRecord
ActiveRecord/Compiler