ORM C++
Loading...
Searching...
No Matches
Model

  1. Create a modelCreate a model
  1. Supported field typesSupported field types
  1. Optional fieldsOptional fields
  1. Table nameTable name
  1. Column namesColumn names
  1. Primary keyPrimary key
  1. Auto-increment primary keyAuto-increment primary key
  1. One-to-one relationsOne-to-one relations
  1. Current limitationsCurrent limitations

Create a model

A model is a reflected C++ struct whose fields can be mapped to SQLite columns.

struct User {
int id;
std::string name;
std::string email;
};

By default the table name is derived from the C++ type name and :: is replaced with _.

Supported field types

SQLite models currently support these scalar C++ field types:

  • bool
  • char, signed char, unsigned char
  • short, short int, unsigned short, short unsigned int
  • int
  • long, long int, unsigned int, unsigned long, long unsigned int
  • long long, long long int, __int64
  • unsigned long long, long long unsigned int, unsigned __int64
  • float
  • double
  • std::string

These types are mapped to SQLite storage classes by the SQLite backend. Types outside this list are not supported as scalar columns.

Optional fields

Wrap a supported scalar type in std::optional<T> to make the column nullable.

struct User {
int id;
std::optional<std::string> email;
};

Non-optional fields are generated as NOT NULL. Optional fields are generated without NOT NULL, and std::nullopt is stored and read back as SQL NULL.

Table name

Override the generated table name with a static table_name field:

struct User {
inline static constexpr std::string_view table_name = "users";
int id;
std::string name;
};

Column names

Override database column names with a static columns_names mapping. The mapping uses C++ field names as keys. Fields omitted from the mapping keep their C++ field names.

struct User {
inline static const std::map<std::string, std::string> columns_names = {
{"id", "user_id"},
{"displayName", "display_name"},
};
int id;
std::string displayName;
};

Query and update builders still use C++ field names such as col("displayName"); the renderer maps them to database column names.

Primary key

If a model has an id field, it is used as the default primary key.

struct User {
int id;
std::string name;
};

Override the primary key with id_columns. Values are C++ field names, not database column names.

struct User {
inline static const std::vector<std::string> id_columns = {"tenantId", "name"};
int id;
int tenantId;
std::string name;
};

To create a model without a primary key, omit id or define an empty id_columns collection.

struct LogEntry {
inline static const std::vector<std::string> id_columns = {};
std::string message;
};

Auto-increment primary key

SQLite integer primary keys can be generated by the database. To enable this, define auto_increment_columns with the C++ field name of the primary-key field:

struct User {
inline static const std::vector<std::string> auto_increment_columns = {"id"};
int id;
std::string name;
};

This creates id INTEGER PRIMARY KEY AUTOINCREMENT and omits the field from generated INSERT statements. Existing models are unchanged unless they define auto_increment_columns.

Auto-increment support has these limitations:

  • The auto-increment column must be the only primary-key column.
  • The column must have type int.
  • The column cannot be std::optional.
  • The column cannot be a related model field.

If columns_names maps the field name, auto_increment_columns still uses the C++ field name:

struct User {
inline static const std::vector<std::string> auto_increment_columns = {"id"};
inline static const std::map<std::string, std::string> columns_names = {
{"id", "user_id"},
};
int id;
std::string name;
};

This creates user_id INTEGER PRIMARY KEY AUTOINCREMENT.

One-to-one relations

A field whose type is another model with a primary key is treated as a one-to-one relation. The owning table stores the related model primary key as local foreign key column(s).

struct Profile {
int id;
std::string city;
};
struct User {
int id;
Profile profile;
};

For this model, User stores profile_id and references Profile(id). Selecting a model joins one-to-one relations by default. Use Query<T>::disableJoining() to read only related primary-key values.

Relations can also be nullable:

struct User {
int id;
std::optional<Profile> profile;
};

Nullable relations generate nullable foreign-key columns, store std::nullopt as SQL NULL, and read SQL NULL back as std::nullopt.

Current limitations

Model metadata currently supports one level of one-to-one relations. It does not yet support OneToMany, ManyToMany, nested relation paths beyond one relation field, custom converters, date/time fields, UUID fields, or boost::optional.