| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154 |
- using Invercargill.DataStructures;
- using Invercargill.Mapping;
- namespace InvercargillSql.Orm {
-
- /**
- * EntityMapper wraps PropertyMapper<T> and adds ORM-specific metadata.
- *
- * This class is the core of the ORM system, providing bidirectional mapping
- * between entity objects and database records. It maintains column definitions
- * and schema metadata needed for SQL generation.
- *
- * Schema metadata (primary key, auto-increment, etc.) is discovered through
- * database introspection when using register_with_schema<T>().
- *
- * Example usage:
- * {{{
- * var mapper = EntityMapper.build_for<User>(b => b
- * .table("users")
- * .column<int64>("id", u => u.id, (u, v) => u.id = v)
- * .column<string>("name", u => u.name, (u, v) => u.name = v));
- * }}}
- */
- public class EntityMapper<T> : Object {
- /**
- * The database table name for this entity.
- */
- public string table_name { get; internal set; }
-
- /**
- * The underlying PropertyMapper used for entity materialization.
- */
- public PropertyMapper<T> property_mapper { get; internal set; }
-
- /**
- * Column definitions for this entity.
- */
- public Vector<ColumnDefinition> columns { get; internal set; }
-
- /**
- * The introspected table schema, or null if not using schema introspection.
- */
- public TableSchema? table_schema { get; internal set; }
-
- /**
- * The name of the primary key column, or null if not defined.
- *
- * This is set either through schema introspection or defaults to "id".
- */
- public string? primary_key_column { get; internal set; }
-
- /**
- * Creates an EntityMapper using a builder function.
- *
- * This is the recommended way to create EntityMapper instances.
- *
- * @param func A builder function that configures the mapper
- * @return A fully configured EntityMapper instance
- *
- * Example:
- * {{{
- * var mapper = EntityMapper.build_for<User>(b => b
- * .table("users")
- * .column<int64>("id", u => u.id, (u, v) => u.id = v)
- * .column<string>("name", u => u.name, (u, v) => u.name = v));
- * }}}
- */
- public static EntityMapper<T> build_for<T>(owned GLib.Func<EntityMapperBuilder<T>> func) {
- var builder = new EntityMapperBuilder<T>();
- func(builder);
- return builder.build();
- }
-
- /**
- * Materializes an entity from a Properties collection.
- *
- * This method is typically called with the results of a database query,
- * where column names map to property names.
- *
- * @param properties The property values from a database row
- * @return A new entity instance populated with the property values
- * @throws Error if materialization fails
- */
- public T materialise(Invercargill.Properties properties) throws Error {
- return property_mapper.materialise(properties);
- }
-
- /**
- * Maps an entity to a Properties collection.
- *
- * This method is used when preparing entity data for database insertion
- * or update operations.
- *
- * @param entity The entity to map
- * @return A Properties collection containing the entity's values
- * @throws Error if mapping fails
- */
- public Invercargill.Properties map_from(T entity) throws Error {
- return property_mapper.map_from(entity);
- }
-
- /**
- * Checks if a column is auto-incrementing.
- *
- * This method uses schema introspection data if available.
- *
- * @param column_name The column name to check
- * @return true if the column is auto-incrementing
- */
- public bool is_auto_increment(string column_name) {
- if (table_schema != null) {
- var col = table_schema.get_column(column_name);
- return col != null && col.auto_increment;
- }
- return false;
- }
-
- /**
- * Gets the effective primary key column name.
- *
- * Returns the primary key from schema introspection if available,
- * otherwise returns the explicitly set primary_key_column,
- * otherwise defaults to "id".
- *
- * @return The primary key column name
- */
- public string get_effective_primary_key() {
- if (table_schema != null && table_schema.primary_key_column != null) {
- return table_schema.primary_key_column;
- }
- return primary_key_column ?? "id";
- }
-
- /**
- * Sets a property value on an existing entity.
- *
- * This method is used to back-populate generated values (like auto-increment
- * primary keys) after an insert operation.
- *
- * @param entity The entity to modify
- * @param column_name The column/property name to set
- * @param value The value to set (will be converted to appropriate type)
- * @throws Error if the property cannot be set
- */
- public void set_property_value(T entity, string column_name, int64 value) throws Error {
- // Create a Properties collection with just this value
- var props = new PropertyDictionary();
- props.set_native<int64?>(column_name, value);
-
- // Use the PropertyMapper's map_into to set the value on the existing entity
- property_mapper.map_into(entity, props);
- }
- }
- }
|