|
@@ -124,6 +124,67 @@ namespace InvercargillSql.Orm {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * Inserts an entity into the database asynchronously.
|
|
|
|
|
+ *
|
|
|
|
|
+ * This method performs the same operation as insert() but in a non-blocking
|
|
|
|
|
+ * manner, allowing the main loop to process other events while waiting
|
|
|
|
|
+ * for the database operation to complete.
|
|
|
|
|
+ *
|
|
|
|
|
+ * After insertion, if the entity has an auto-increment primary key,
|
|
|
|
|
+ * the key value is back-populated into the entity.
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param entity The entity to insert
|
|
|
|
|
+ * @throws SqlError if insertion fails
|
|
|
|
|
+ */
|
|
|
|
|
+ public async void insert_async<T>(T entity) throws Error {
|
|
|
|
|
+ var mapper = get_mapper<T>();
|
|
|
|
|
+ Invercargill.Properties properties;
|
|
|
|
|
+ try {
|
|
|
|
|
+ properties = mapper.map_from(entity);
|
|
|
|
|
+ } catch (Error e) {
|
|
|
|
|
+ throw new SqlError.GENERAL_ERROR("Failed to map entity: %s".printf(e.message));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Build column list, excluding auto-increment columns
|
|
|
|
|
+ var columns = new Vector<string>();
|
|
|
|
|
+ foreach (var col in mapper.columns) {
|
|
|
|
|
+ if (!mapper.is_auto_increment(col.name)) {
|
|
|
|
|
+ columns.add(col.name);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ var sql = _dialect.build_insert_sql(mapper.table_name, columns);
|
|
|
|
|
+ var command = _connection.create_command(sql);
|
|
|
|
|
+
|
|
|
|
|
+ // Add parameters in column order (excluding auto-increment)
|
|
|
|
|
+ foreach (var col in mapper.columns) {
|
|
|
|
|
+ if (mapper.is_auto_increment(col.name)) {
|
|
|
|
|
+ continue; // Skip auto-increment columns
|
|
|
|
|
+ }
|
|
|
|
|
+ var value = properties.get(col.name);
|
|
|
|
|
+ if (value != null) {
|
|
|
|
|
+ command.with_parameter<Invercargill.Element>(col.name, value);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ command.with_null(col.name);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Execute asynchronously
|
|
|
|
|
+ yield command.execute_non_query_async();
|
|
|
|
|
+
|
|
|
|
|
+ // Back-populate the generated primary key
|
|
|
|
|
+ var pk_column = mapper.get_effective_primary_key();
|
|
|
|
|
+ if (pk_column != null && mapper.is_auto_increment(pk_column)) {
|
|
|
|
|
+ int64 generated_id = _connection.last_insert_rowid;
|
|
|
|
|
+ try {
|
|
|
|
|
+ mapper.set_property_value(entity, pk_column, generated_id);
|
|
|
|
|
+ } catch (Error e) {
|
|
|
|
|
+ throw new SqlError.GENERAL_ERROR("Failed to back-populate primary key: %s".printf(e.message));
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
/**
|
|
/**
|
|
|
* Updates an entity in the database.
|
|
* Updates an entity in the database.
|
|
|
*
|
|
*
|
|
@@ -169,6 +230,58 @@ namespace InvercargillSql.Orm {
|
|
|
command.execute_non_query();
|
|
command.execute_non_query();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * Updates an entity in the database asynchronously.
|
|
|
|
|
+ *
|
|
|
|
|
+ * This method performs the same operation as update() but in a non-blocking
|
|
|
|
|
+ * manner, allowing the main loop to process other events while waiting
|
|
|
|
|
+ * for the database operation to complete.
|
|
|
|
|
+ *
|
|
|
|
|
+ * The entity is identified by its primary key.
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param entity The entity to update
|
|
|
|
|
+ * @throws SqlError if update fails
|
|
|
|
|
+ */
|
|
|
|
|
+ public async void update_async<T>(T entity) throws Error {
|
|
|
|
|
+ var mapper = get_mapper<T>();
|
|
|
|
|
+ Invercargill.Properties properties;
|
|
|
|
|
+ try {
|
|
|
|
|
+ properties = mapper.map_from(entity);
|
|
|
|
|
+ } catch (Error e) {
|
|
|
|
|
+ throw new SqlError.GENERAL_ERROR("Failed to map entity: %s".printf(e.message));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ var columns = new Vector<string>();
|
|
|
|
|
+ foreach (var col in mapper.columns) {
|
|
|
|
|
+ columns.add(col.name);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ var pk_column = mapper.get_effective_primary_key();
|
|
|
|
|
+ var sql = _dialect.build_update_sql(mapper.table_name, columns, pk_column);
|
|
|
|
|
+ var command = _connection.create_command(sql);
|
|
|
|
|
+
|
|
|
|
|
+ // Add parameters for SET clause
|
|
|
|
|
+ foreach (var col in mapper.columns) {
|
|
|
|
|
+ var value = properties.get(col.name);
|
|
|
|
|
+ if (value != null) {
|
|
|
|
|
+ command.with_parameter<Invercargill.Element>(col.name, value);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ command.with_null(col.name);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Add primary key parameter for WHERE clause
|
|
|
|
|
+ var pk_value = properties.get(pk_column);
|
|
|
|
|
+ if (pk_value != null) {
|
|
|
|
|
+ command.with_parameter<Invercargill.Element>(pk_column, pk_value);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ command.with_null(pk_column);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Execute asynchronously
|
|
|
|
|
+ yield command.execute_non_query_async();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
/**
|
|
/**
|
|
|
* Deletes an entity from the database.
|
|
* Deletes an entity from the database.
|
|
|
*
|
|
*
|
|
@@ -198,6 +311,42 @@ namespace InvercargillSql.Orm {
|
|
|
command.execute_non_query();
|
|
command.execute_non_query();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * Deletes an entity from the database asynchronously.
|
|
|
|
|
+ *
|
|
|
|
|
+ * This method performs the same operation as delete() but in a non-blocking
|
|
|
|
|
+ * manner, allowing the main loop to process other events while waiting
|
|
|
|
|
+ * for the database operation to complete.
|
|
|
|
|
+ *
|
|
|
|
|
+ * The entity is identified by its primary key.
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param entity The entity to delete
|
|
|
|
|
+ * @throws SqlError if deletion fails
|
|
|
|
|
+ */
|
|
|
|
|
+ public async void delete_async<T>(T entity) throws Error {
|
|
|
|
|
+ var mapper = get_mapper<T>();
|
|
|
|
|
+ Invercargill.Properties properties;
|
|
|
|
|
+ try {
|
|
|
|
|
+ properties = mapper.map_from(entity);
|
|
|
|
|
+ } catch (Error e) {
|
|
|
|
|
+ throw new SqlError.GENERAL_ERROR("Failed to map entity: %s".printf(e.message));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ var pk_column = mapper.get_effective_primary_key();
|
|
|
|
|
+ var sql = _dialect.build_delete_sql(mapper.table_name, pk_column);
|
|
|
|
|
+ var command = _connection.create_command(sql);
|
|
|
|
|
+
|
|
|
|
|
+ var pk_value = properties.get(pk_column);
|
|
|
|
|
+ if (pk_value != null) {
|
|
|
|
|
+ command.with_parameter<Invercargill.Element>(pk_column, pk_value);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ command.with_null(pk_column);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Execute asynchronously
|
|
|
|
|
+ yield command.execute_non_query_async();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
/**
|
|
/**
|
|
|
* Gets the SQL dialect for internal use.
|
|
* Gets the SQL dialect for internal use.
|
|
|
* Used by EntityQuery and ProjectionQuery to build SQL.
|
|
* Used by EntityQuery and ProjectionQuery to build SQL.
|