diff --git a/include/lardon3d/project_db.h b/include/lardon3d/project_db.h index 4ad871f..7b0cf54 100644 --- a/include/lardon3d/project_db.h +++ b/include/lardon3d/project_db.h @@ -505,6 +505,11 @@ Lardon3DProjectDbResult lardon3d_project_db_register_image_asset( Lardon3DProjectDb *database, const unsigned char sha256[LARDON3D_PROJECT_DB_SHA256_SIZE], const char *asset_path, uint64_t size_bytes, int64_t created_at, Lardon3DProjectDbImageAsset *asset); +Lardon3DProjectDbResult lardon3d_project_db_publish_derived_capture_image( + Lardon3DProjectDb *database, uint64_t capture_id, uint64_t asset_id, + const char *original_name, const char *source_path, uint64_t producer_task_id, + int64_t imported_at, Lardon3DProjectDbImageRegisterStatus *status, + Lardon3DProjectDbImage *image); Lardon3DProjectDbResult lardon3d_project_db_load_image(Lardon3DProjectDb *database, uint64_t image_id, Lardon3DProjectDbImage *image, diff --git a/src/project_db.c b/src/project_db.c index 1242675..278897d 100644 --- a/src/project_db.c +++ b/src/project_db.c @@ -2584,6 +2584,55 @@ static Lardon3DProjectDbResult ensure_capture_for_registered_image_locked( return result; } +static Lardon3DProjectDbResult insert_or_find_image_locked( + Lardon3DProjectDb *database, uint64_t scanset_id, uint64_t asset_id, + const char *original_name, const char *source_path, uint64_t producer_task_id, + int64_t imported_at, int *inserted, uint64_t *image_id) { + sqlite3_stmt *statement = NULL; + Lardon3DProjectDbResult result = prepare( + database, + "INSERT INTO images(scanset_id,asset_id,original_name,source_path,producer_task_id," + "imported_at) VALUES(?1,?2,?3,?4,?5,?6) ON CONFLICT(scanset_id,asset_id) DO NOTHING", + &statement); + if (result == LARDON3D_PROJECT_DB_OK) { + (void)sqlite3_bind_int64(statement, 1, (sqlite3_int64)scanset_id); + (void)sqlite3_bind_int64(statement, 2, (sqlite3_int64)asset_id); + (void)sqlite3_bind_text(statement, 3, original_name, -1, SQLITE_TRANSIENT); + (void)sqlite3_bind_text(statement, 4, source_path, -1, SQLITE_TRANSIENT); + if (producer_task_id) { + (void)sqlite3_bind_int64(statement, 5, (sqlite3_int64)producer_task_id); + } else { + (void)sqlite3_bind_null(statement, 5); + } + (void)sqlite3_bind_int64(statement, 6, imported_at); + result = step_done(database, statement, "insert logical image"); + statement = NULL; + } + if (result == LARDON3D_PROJECT_DB_OK) { + *inserted = sqlite3_changes(database->connection); + result = prepare(database, "SELECT image_id FROM images WHERE scanset_id=?1 AND asset_id=?2", + &statement); + } + if (result == LARDON3D_PROJECT_DB_OK) { + (void)sqlite3_bind_int64(statement, 1, (sqlite3_int64)scanset_id); + (void)sqlite3_bind_int64(statement, 2, (sqlite3_int64)asset_id); + int code = sqlite3_step(statement); + if (code == SQLITE_ROW) { + sqlite3_int64 stored_image_id = sqlite3_column_int64(statement, 0); + if (stored_image_id <= 0) { + result = LARDON3D_PROJECT_DB_CORRUPT; + } else { + *image_id = (uint64_t)stored_image_id; + } + } else { + result = code == SQLITE_DONE ? LARDON3D_PROJECT_DB_CORRUPT + : sqlite_result(database, code, "load registered image"); + } + (void)sqlite3_finalize(statement); + } + return result; +} + Lardon3DProjectDbResult lardon3d_project_db_register_image_asset( Lardon3DProjectDb *database, const unsigned char sha256[LARDON3D_PROJECT_DB_SHA256_SIZE], const char *asset_path, @@ -2717,48 +2766,16 @@ Lardon3DProjectDbResult lardon3d_project_db_register_image( (void)sqlite3_finalize(statement); statement = NULL; } - if (result == LARDON3D_PROJECT_DB_OK) { - result = prepare( - database, - "INSERT INTO " - "images(scanset_id,asset_id,original_name,source_path,producer_task_id,imported_at) " - "VALUES(?1,?2,?3,?4,?5,?6) ON CONFLICT(scanset_id,asset_id) DO NOTHING", - &statement); - } int inserted = 0; + uint64_t image_id = 0; if (result == LARDON3D_PROJECT_DB_OK) { - (void)sqlite3_bind_int64(statement, 1, (sqlite3_int64)scanset_id); - (void)sqlite3_bind_int64(statement, 2, asset_id); - (void)sqlite3_bind_text(statement, 3, original_name, -1, SQLITE_TRANSIENT); - (void)sqlite3_bind_text(statement, 4, source_path, -1, SQLITE_TRANSIENT); - if (producer_task_id) { - (void)sqlite3_bind_int64(statement, 5, (sqlite3_int64)producer_task_id); - } else { - (void)sqlite3_bind_null(statement, 5); - } - (void)sqlite3_bind_int64(statement, 6, imported_at); - result = step_done(database, statement, "insert logical image"); - statement = NULL; - inserted = sqlite3_changes(database->connection); - } - sqlite3_int64 image_id = 0; - if (result == LARDON3D_PROJECT_DB_OK) { - result = prepare(database, "SELECT image_id FROM images WHERE scanset_id=?1 AND asset_id=?2", - &statement); - } - if (result == LARDON3D_PROJECT_DB_OK) { - (void)sqlite3_bind_int64(statement, 1, (sqlite3_int64)scanset_id); - (void)sqlite3_bind_int64(statement, 2, asset_id); - int code = sqlite3_step(statement); - if (code != SQLITE_ROW || (image_id = sqlite3_column_int64(statement, 0)) <= 0) { - result = LARDON3D_PROJECT_DB_CORRUPT; - } - (void)sqlite3_finalize(statement); - statement = NULL; + result = insert_or_find_image_locked(database, scanset_id, (uint64_t)asset_id, original_name, + source_path, producer_task_id, imported_at, &inserted, + &image_id); } if (result == LARDON3D_PROJECT_DB_OK) { result = ensure_capture_for_registered_image_locked(database, scanset_id, (uint64_t)asset_id, - (uint64_t)image_id); + image_id); } if (result == LARDON3D_PROJECT_DB_OK) { result = execute(database, "COMMIT", "commit image register"); @@ -2772,7 +2789,164 @@ Lardon3DProjectDbResult lardon3d_project_db_register_image( } *status = inserted == 1 ? LARDON3D_PROJECT_DB_IMAGE_REGISTERED : LARDON3D_PROJECT_DB_IMAGE_ALREADY_PRESENT; - return lardon3d_project_db_load_image(database, (uint64_t)image_id, image, + return lardon3d_project_db_load_image(database, image_id, image, + &(Lardon3DProjectDbImageAsset){0}); +} + +Lardon3DProjectDbResult lardon3d_project_db_publish_derived_capture_image( + Lardon3DProjectDb *database, uint64_t capture_id, uint64_t asset_id, + const char *original_name, const char *source_path, uint64_t producer_task_id, + int64_t imported_at, Lardon3DProjectDbImageRegisterStatus *status, + Lardon3DProjectDbImage *image) { + if (!database || !valid_catalog_id(capture_id) || !valid_catalog_id(asset_id) || + !valid_original_name(original_name) || + !bounded_text(source_path, LARDON3D_PROJECT_DB_PATH_CAPACITY, false) || + (producer_task_id != 0 && !valid_task_id(producer_task_id)) || imported_at < 0 || !status || + !image) { + return LARDON3D_PROJECT_DB_INVALID_ARGUMENT; + } + + memset(image, 0, sizeof(*image)); + *status = LARDON3D_PROJECT_DB_IMAGE_REGISTERED; + (void)pthread_mutex_lock(&database->mutex); + Lardon3DProjectDbResult result = + execute(database, "BEGIN IMMEDIATE", "begin derived capture image publication"); + sqlite3_stmt *statement = NULL; + sqlite3_int64 scanset_id = 0; + if (result == LARDON3D_PROJECT_DB_OK) { + result = prepare(database, "SELECT scanset_id FROM captures WHERE capture_id=?1", &statement); + } + if (result == LARDON3D_PROJECT_DB_OK) { + (void)sqlite3_bind_int64(statement, 1, (sqlite3_int64)capture_id); + int code = sqlite3_step(statement); + if (code == SQLITE_DONE) { + result = LARDON3D_PROJECT_DB_NOT_FOUND; + } else if (code != SQLITE_ROW || (scanset_id = sqlite3_column_int64(statement, 0)) <= 0) { + result = code == SQLITE_ROW ? LARDON3D_PROJECT_DB_CORRUPT + : sqlite_result(database, code, "load derived image capture"); + } + (void)sqlite3_finalize(statement); + statement = NULL; + } + if (result == LARDON3D_PROJECT_DB_OK) { + result = prepare(database, "SELECT 1 FROM image_assets WHERE asset_id=?1", &statement); + } + if (result == LARDON3D_PROJECT_DB_OK) { + (void)sqlite3_bind_int64(statement, 1, (sqlite3_int64)asset_id); + int code = sqlite3_step(statement); + if (code == SQLITE_DONE) { + result = LARDON3D_PROJECT_DB_NOT_FOUND; + } else if (code != SQLITE_ROW) { + result = sqlite_result(database, code, "load derived image asset"); + } + (void)sqlite3_finalize(statement); + statement = NULL; + } + if (result == LARDON3D_PROJECT_DB_OK) { + result = prepare( + database, + "SELECT 1 FROM asset_derivations d JOIN capture_assets p " + "ON p.asset_id=d.parent_asset_id WHERE d.child_asset_id=?1 AND p.capture_id=?2", + &statement); + } + if (result == LARDON3D_PROJECT_DB_OK) { + (void)sqlite3_bind_int64(statement, 1, (sqlite3_int64)asset_id); + (void)sqlite3_bind_int64(statement, 2, (sqlite3_int64)capture_id); + int code = sqlite3_step(statement); + if (code == SQLITE_DONE) { + result = LARDON3D_PROJECT_DB_CONSTRAINT; + } else if (code != SQLITE_ROW) { + result = sqlite_result(database, code, "load derived image provenance"); + } + (void)sqlite3_finalize(statement); + statement = NULL; + } + + int inserted = 0; + uint64_t image_id = 0; + if (result == LARDON3D_PROJECT_DB_OK) { + result = insert_or_find_image_locked(database, (uint64_t)scanset_id, asset_id, original_name, + source_path, producer_task_id, imported_at, &inserted, + &image_id); + } + + sqlite3_int64 mapped_capture_id = 0; + if (result == LARDON3D_PROJECT_DB_OK) { + result = prepare(database, "SELECT capture_id FROM capture_images WHERE image_id=?1", &statement); + } + if (result == LARDON3D_PROJECT_DB_OK) { + (void)sqlite3_bind_int64(statement, 1, (sqlite3_int64)image_id); + int code = sqlite3_step(statement); + if (code == SQLITE_ROW) { + mapped_capture_id = sqlite3_column_int64(statement, 0); + if (mapped_capture_id <= 0) { + result = LARDON3D_PROJECT_DB_CORRUPT; + } else if ((uint64_t)mapped_capture_id != capture_id) { + result = LARDON3D_PROJECT_DB_CONSTRAINT; + } + } else if (code != SQLITE_DONE) { + result = sqlite_result(database, code, "find derived image capture"); + } + (void)sqlite3_finalize(statement); + statement = NULL; + } + + if (result == LARDON3D_PROJECT_DB_OK) { + result = prepare(database, "SELECT role FROM capture_assets WHERE capture_id=?1 AND asset_id=?2", + &statement); + } + if (result == LARDON3D_PROJECT_DB_OK) { + (void)sqlite3_bind_int64(statement, 1, (sqlite3_int64)capture_id); + (void)sqlite3_bind_int64(statement, 2, (sqlite3_int64)asset_id); + int code = sqlite3_step(statement); + if (code == SQLITE_ROW) { + if (sqlite3_column_int(statement, 0) != LARDON3D_DB_CAPTURE_ASSET_DERIVED) { + result = LARDON3D_PROJECT_DB_CONSTRAINT; + } + } else if (code == SQLITE_DONE) { + (void)sqlite3_finalize(statement); + statement = NULL; + result = prepare(database, + "INSERT INTO capture_assets(capture_id,asset_id,role) VALUES(?1,?2,?3)", + &statement); + if (result == LARDON3D_PROJECT_DB_OK) { + (void)sqlite3_bind_int64(statement, 1, (sqlite3_int64)capture_id); + (void)sqlite3_bind_int64(statement, 2, (sqlite3_int64)asset_id); + (void)sqlite3_bind_int(statement, 3, LARDON3D_DB_CAPTURE_ASSET_DERIVED); + result = step_done(database, statement, "attach derived capture asset"); + statement = NULL; + } + } else { + result = sqlite_result(database, code, "find derived capture asset"); + } + if (statement) { + (void)sqlite3_finalize(statement); + statement = NULL; + } + } + if (result == LARDON3D_PROJECT_DB_OK && mapped_capture_id == 0) { + result = prepare(database, "INSERT INTO capture_images(capture_id,image_id) VALUES(?1,?2)", + &statement); + } + if (result == LARDON3D_PROJECT_DB_OK && mapped_capture_id == 0) { + (void)sqlite3_bind_int64(statement, 1, (sqlite3_int64)capture_id); + (void)sqlite3_bind_int64(statement, 2, (sqlite3_int64)image_id); + result = step_done(database, statement, "attach derived capture image"); + statement = NULL; + } + if (result == LARDON3D_PROJECT_DB_OK) { + result = execute(database, "COMMIT", "commit derived capture image publication"); + } + if (result != LARDON3D_PROJECT_DB_OK) { + (void)execute(database, "ROLLBACK", "rollback derived capture image publication"); + } + (void)pthread_mutex_unlock(&database->mutex); + if (result != LARDON3D_PROJECT_DB_OK) { + return result; + } + *status = inserted == 1 ? LARDON3D_PROJECT_DB_IMAGE_REGISTERED + : LARDON3D_PROJECT_DB_IMAGE_ALREADY_PRESENT; + return lardon3d_project_db_load_image(database, image_id, image, &(Lardon3DProjectDbImageAsset){0}); } diff --git a/tests/test_project_db.c b/tests/test_project_db.c index ae3b8bc..4c61f95 100644 --- a/tests/test_project_db.c +++ b/tests/test_project_db.c @@ -1105,42 +1105,76 @@ static bool run_test(void) { unsigned char developed_hash[LARDON3D_PROJECT_DB_SHA256_SIZE] = {6}; char developed_asset_path[LARDON3D_PROJECT_DB_PATH_CAPACITY]; asset_path_for_hash(developed_hash, developed_asset_path); + Lardon3DProjectDbImageAsset developed_asset; Lardon3DProjectDbImage developed_image; - CHECK(lardon3d_project_db_register_image( - database, replacement_scanset.scanset_id, developed_hash, developed_asset_path, 3, - "developed.png", "/source/developed.png", 0, 23, &identity_status, - &developed_image) == LARDON3D_PROJECT_DB_OK); - Lardon3DProjectDbCapture developed_capture; + CHECK(lardon3d_project_db_register_image_asset(database, developed_hash, developed_asset_path, 3, + 23, &developed_asset) == + LARDON3D_PROJECT_DB_OK); + CHECK(lardon3d_project_db_publish_derived_capture_image( + database, capture.capture_id, developed_asset.asset_id, "developed.png", + "/source/developed.png", 0, 23, &identity_status, &developed_image) == + LARDON3D_PROJECT_DB_CONSTRAINT); + Lardon3DProjectDbAssetDerivation derivation = { + .parent_asset_id = raw_asset.asset_id, + .child_asset_id = developed_asset.asset_id, + .kind = LARDON3D_DB_ASSET_DERIVATION_GENERIC_VERSIONED, + .version = 1, + .created_at = 24}; + memset(derivation.parameter_fingerprint, 0xA5, sizeof(derivation.parameter_fingerprint)); + CHECK(lardon3d_project_db_record_asset_derivation(database, &derivation) == + LARDON3D_PROJECT_DB_OK); + Lardon3DProjectDbCapture capture_page_before[8]; + size_t capture_count_before = 0; + CHECK(lardon3d_project_db_list_captures(database, replacement_scanset.scanset_id, 0, + capture_page_before, 8, &capture_count_before) == + LARDON3D_PROJECT_DB_OK); + CHECK(lardon3d_project_db_publish_derived_capture_image( + database, capture.capture_id, developed_asset.asset_id, "developed.png", + "/source/developed.png", 0, 23, &identity_status, &developed_image) == + LARDON3D_PROJECT_DB_OK && + identity_status == LARDON3D_PROJECT_DB_IMAGE_REGISTERED && + developed_image.scanset_id == capture.scanset_id && + developed_image.asset_id == developed_asset.asset_id); + Lardon3DProjectDbCapture mapped_developed_capture; CHECK(lardon3d_project_db_find_capture_for_image(database, developed_image.image_id, - &developed_capture) == LARDON3D_PROJECT_DB_OK); - lardon3d_project_db_close(database); - database = NULL; - char remove_developed_capture[256]; - CHECK(snprintf(remove_developed_capture, sizeof(remove_developed_capture), - "PRAGMA foreign_keys=ON;DELETE FROM captures WHERE capture_id=%llu", - (unsigned long long)developed_capture.capture_id) > 0); - CHECK(execute_test_sql(database_path, remove_developed_capture)); - CHECK(lardon3d_project_db_open(database_path, &database, error) == LARDON3D_PROJECT_DB_OK); - CHECK(lardon3d_project_db_attach_capture_asset( - database, capture.capture_id, developed_image.asset_id, - LARDON3D_DB_CAPTURE_ASSET_DERIVED) == LARDON3D_PROJECT_DB_OK); + &mapped_developed_capture) == + LARDON3D_PROJECT_DB_OK && + mapped_developed_capture.capture_id == capture.capture_id); + Lardon3DProjectDbCapture capture_page_after[8]; + size_t capture_count_after = 0; + CHECK(lardon3d_project_db_list_captures(database, replacement_scanset.scanset_id, 0, + capture_page_after, 8, &capture_count_after) == + LARDON3D_PROJECT_DB_OK && + capture_count_after == capture_count_before); Lardon3DProjectDbCaptureAsset capture_assets[3]; size_t capture_asset_count = 0; CHECK(lardon3d_project_db_list_capture_assets(database, capture.capture_id, 0, capture_assets, 3, &capture_asset_count) == LARDON3D_PROJECT_DB_OK && capture_asset_count == 3); + bool found_original_source = false; + bool found_derived_asset = false; + for (size_t i = 0; i < capture_asset_count; ++i) { + found_original_source = found_original_source || + (capture_assets[i].asset_id == pair_image.asset_id && + capture_assets[i].role == LARDON3D_DB_CAPTURE_ASSET_SOURCE); + found_derived_asset = found_derived_asset || + (capture_assets[i].asset_id == developed_asset.asset_id && + capture_assets[i].role == LARDON3D_DB_CAPTURE_ASSET_DERIVED); + } + CHECK(found_original_source && found_derived_asset); CHECK(lardon3d_project_db_attach_capture_image(database, capture.capture_id, pair_image.image_id) == LARDON3D_PROJECT_DB_CONSTRAINT); CHECK(lardon3d_project_db_attach_capture_image(database, other_capture.capture_id, pair_image.image_id) == LARDON3D_PROJECT_DB_CONSTRAINT); - CHECK(lardon3d_project_db_attach_capture_image(database, capture.capture_id, - developed_image.image_id) == - LARDON3D_PROJECT_DB_OK); CHECK(lardon3d_project_db_find_capture_for_image(database, pair_image.image_id, &mapped_capture) == LARDON3D_PROJECT_DB_OK && mapped_capture.capture_id == capture.capture_id); + CHECK(lardon3d_project_db_get_selected_capture_image(database, capture.capture_id, + &selected_image) == + LARDON3D_PROJECT_DB_OK && + selected_image == pair_image.image_id); CHECK(lardon3d_project_db_set_selected_capture_image(database, capture.capture_id, pair_image.image_id) == LARDON3D_PROJECT_DB_OK); @@ -1163,27 +1197,111 @@ static bool run_test(void) { &selected_image) == LARDON3D_PROJECT_DB_OK && selected_image == developed_image.image_id); - CHECK(query_integer(database_path, "SELECT count(*) FROM asset_derivations", 0)); - Lardon3DProjectDbAssetDerivation derivation = { - .parent_asset_id = raw_asset.asset_id, - .child_asset_id = developed_image.asset_id, - .kind = LARDON3D_DB_ASSET_DERIVATION_GENERIC_VERSIONED, - .version = 1, - .created_at = 24}; - memset(derivation.parameter_fingerprint, 0xA5, sizeof(derivation.parameter_fingerprint)); + Lardon3DProjectDbImage republished_developed_image; + CHECK(lardon3d_project_db_publish_derived_capture_image( + database, capture.capture_id, developed_asset.asset_id, "developed.png", + "/source/developed.png", 0, 23, &identity_status, &republished_developed_image) == + LARDON3D_PROJECT_DB_OK && + identity_status == LARDON3D_PROJECT_DB_IMAGE_ALREADY_PRESENT && + republished_developed_image.image_id == developed_image.image_id); + CHECK(lardon3d_project_db_get_selected_capture_image(database, capture.capture_id, + &selected_image) == + LARDON3D_PROJECT_DB_OK && + selected_image == developed_image.image_id); + size_t capture_count_republished = 0; + CHECK(lardon3d_project_db_list_captures(database, replacement_scanset.scanset_id, 0, + capture_page_after, 8, &capture_count_republished) == + LARDON3D_PROJECT_DB_OK && + capture_count_republished == capture_count_after); + CHECK(lardon3d_project_db_publish_derived_capture_image( + database, UINT64_C(999999), developed_asset.asset_id, "developed.png", + "/source/developed.png", 0, 23, &identity_status, &republished_developed_image) == + LARDON3D_PROJECT_DB_NOT_FOUND); + CHECK(lardon3d_project_db_publish_derived_capture_image( + database, capture.capture_id, UINT64_C(999999), "missing.png", "/source/missing.png", + 0, 23, &identity_status, &republished_developed_image) == LARDON3D_PROJECT_DB_NOT_FOUND); + unsigned char other_developed_hash[LARDON3D_PROJECT_DB_SHA256_SIZE] = {7}; + char other_developed_asset_path[LARDON3D_PROJECT_DB_PATH_CAPACITY]; + asset_path_for_hash(other_developed_hash, other_developed_asset_path); + Lardon3DProjectDbImageAsset other_developed_asset; + CHECK(lardon3d_project_db_register_image_asset(database, other_developed_hash, + other_developed_asset_path, 4, 25, + &other_developed_asset) == + LARDON3D_PROJECT_DB_OK); + derivation.child_asset_id = other_developed_asset.asset_id; + derivation.parent_asset_id = raw_asset.asset_id; + derivation.created_at = 25; CHECK(lardon3d_project_db_record_asset_derivation(database, &derivation) == LARDON3D_PROJECT_DB_OK); + Lardon3DProjectDbImage other_developed_image; + uint64_t image_count_before_cross_capture = 0; + CHECK(lardon3d_project_db_count_images(database, replacement_scanset.scanset_id, + &image_count_before_cross_capture) == + LARDON3D_PROJECT_DB_OK); + CHECK(lardon3d_project_db_publish_derived_capture_image( + database, other_capture.capture_id, other_developed_asset.asset_id, "other-developed.png", + "/source/other-developed.png", 0, 25, &identity_status, &other_developed_image) == + LARDON3D_PROJECT_DB_CONSTRAINT); + uint64_t image_count_after_cross_capture = 0; + CHECK(lardon3d_project_db_count_images(database, replacement_scanset.scanset_id, + &image_count_after_cross_capture) == + LARDON3D_PROJECT_DB_OK && + image_count_after_cross_capture == image_count_before_cross_capture); + Lardon3DProjectDbCaptureAsset other_capture_assets[1]; + size_t other_capture_asset_count = 0; + CHECK(lardon3d_project_db_list_capture_assets(database, other_capture.capture_id, 0, + other_capture_assets, 1, + &other_capture_asset_count) == + LARDON3D_PROJECT_DB_OK && + other_capture_asset_count == 0); + + unsigned char other_raw_hash[LARDON3D_PROJECT_DB_SHA256_SIZE] = {8}; + char other_raw_asset_path[LARDON3D_PROJECT_DB_PATH_CAPACITY]; + asset_path_for_hash(other_raw_hash, other_raw_asset_path); + Lardon3DProjectDbImageAsset other_raw_asset; + CHECK(lardon3d_project_db_register_image_asset(database, other_raw_hash, other_raw_asset_path, 5, + 26, &other_raw_asset) == + LARDON3D_PROJECT_DB_OK); + CHECK(lardon3d_project_db_attach_capture_asset( + database, other_capture.capture_id, other_raw_asset.asset_id, + LARDON3D_DB_CAPTURE_ASSET_SOURCE) == LARDON3D_PROJECT_DB_OK); + unsigned char owned_developed_hash[LARDON3D_PROJECT_DB_SHA256_SIZE] = {9}; + char owned_developed_asset_path[LARDON3D_PROJECT_DB_PATH_CAPACITY]; + asset_path_for_hash(owned_developed_hash, owned_developed_asset_path); + Lardon3DProjectDbImageAsset owned_developed_asset; + CHECK(lardon3d_project_db_register_image_asset(database, owned_developed_hash, + owned_developed_asset_path, 6, 27, + &owned_developed_asset) == + LARDON3D_PROJECT_DB_OK); + derivation.parent_asset_id = other_raw_asset.asset_id; + derivation.child_asset_id = owned_developed_asset.asset_id; + derivation.created_at = 27; + CHECK(lardon3d_project_db_record_asset_derivation(database, &derivation) == + LARDON3D_PROJECT_DB_OK); + CHECK(lardon3d_project_db_publish_derived_capture_image( + database, other_capture.capture_id, owned_developed_asset.asset_id, + "owned-developed.png", "/source/owned-developed.png", 0, 27, &identity_status, + &other_developed_image) == LARDON3D_PROJECT_DB_OK); + CHECK(lardon3d_project_db_publish_derived_capture_image( + database, capture.capture_id, owned_developed_asset.asset_id, "owned-developed.png", + "/source/owned-developed.png", 0, 27, &identity_status, &republished_developed_image) == + LARDON3D_PROJECT_DB_CONSTRAINT); + CHECK(lardon3d_project_db_find_capture_for_image(database, other_developed_image.image_id, + &mapped_developed_capture) == + LARDON3D_PROJECT_DB_OK && + mapped_developed_capture.capture_id == other_capture.capture_id); Lardon3DProjectDbAssetDerivation loaded_derivation; - CHECK(lardon3d_project_db_load_asset_derivation(database, developed_image.asset_id, + CHECK(lardon3d_project_db_load_asset_derivation(database, developed_asset.asset_id, &loaded_derivation) == LARDON3D_PROJECT_DB_OK && loaded_derivation.parent_asset_id == raw_asset.asset_id && loaded_derivation.version == 1 && memcmp(loaded_derivation.parameter_fingerprint, derivation.parameter_fingerprint, sizeof(derivation.parameter_fingerprint)) == 0); + derivation.child_asset_id = developed_asset.asset_id; derivation.parent_asset_id = pair_image.asset_id; CHECK(lardon3d_project_db_record_asset_derivation(database, &derivation) == LARDON3D_PROJECT_DB_CONSTRAINT); - derivation.parent_asset_id = developed_image.asset_id; + derivation.parent_asset_id = developed_asset.asset_id; CHECK(lardon3d_project_db_record_asset_derivation(database, &derivation) == LARDON3D_PROJECT_DB_INVALID_ARGUMENT);