Resource Schemas
May 26, 2025 ยท View on GitHub
Overview
Schemas in the DoTheWorld library provide a structured way to manage resources in a serializable format. They introduce concepts like primary keys and foreign keys, enabling efficient data organization, retrieval, and manipulation. This allows for database-like operations on resources with improved readability and performance.
This document focuses on how to use schemas to create, remove, find, and iterate over resource insertions. Each operation is accompanied by detailed examples to demonstrate practical usage.
Key Concepts
- Schema: A blueprint for organizing resources with defined rules, such as primary keys.
- Primary Key: A unique identifier for a resource insertion, used for quick lookups.
- Insertion: A single record or entry created under a schema.
- Resource: A fundamental entity in DoTheWorld that can represent files, directories, or data structures.
Creating an Insertion
You can create a new resource insertion within a schema. This example demonstrates how to define a schema for users and insert a new user record with fields like name, email, password, and age.
Example: Creating a User Insertion
#include "doTheWorldOne.c"
int main() {
// Initialize a new resource database
DtwResource *database = new_DtwResource("tests/target/schema_database");
// Create a root schema for the database
DtwDatabaseSchema *root_schema = DtwResource_newDatabaseSchema(database);
// Define a sub-schema for users
DtwSchema *users_schema = DtwDatabaseSchema_new_subSchema(root_schema, "users");
// Set primary keys for unique identification
DtwSchema_add_primary_key(users_schema, "name");
DtwSchema_add_primary_key(users_schema, "email");
// Access the users resource
DtwResource *users = DtwResource_sub_resource(database, "users");
// Create a new user insertion
DtwResource *user = DtwResource_new_schema_insertion(users);
DtwResource_set_string_in_sub_resource(user, "name", "mateus");
DtwResource_set_string_in_sub_resource(user, "email", "mateusmoutinho01@gmail.com");
DtwResource_set_string_sha_in_sub_resource(user, "password", "12345");
DtwResource_set_long_in_sub_resource(user, "age", 27);
// Check for errors
if (DtwResource_error(database)) {
printf("Error: %s\n", DtwResource_get_error_message(database));
}
// Commit changes to persist them
DtwResource_commit(database);
// Free resources to prevent memory leaks
DtwResource_free(database);
return 0;
}
Explanation
- Database Initialization: A resource database is created at the specified path.
- Schema Definition: A root schema is established, with a sub-schema for "users".
- Primary Keys: The fields "name" and "email" are set as primary keys to ensure uniqueness.
- Insertion: A new user is created with fields set using type-specific setters (e.g.,
set_string,set_long,set_string_shafor hashed values). - Error Handling: Any errors during the process are captured and displayed.
- Commit and Cleanup: Changes are saved with
commit, and memory is freed.
Removing an Insertion
You can remove a specific insertion from a schema. This operation also automatically handles the removal of associated indices tied to primary keys.
Example: Removing a User Insertion
#include "doTheWorldOne.c"
// Helper function to create user insertions
void create_users(DtwResource *database, const char *name, const char *email, const char *password, int age) {
DtwResource *users = DtwResource_sub_resource(database, "users");
DtwResource *user = DtwResource_new_schema_insertion(users);
DtwResource_set_string_in_sub_resource(user, "name", name);
DtwResource_set_string_in_sub_resource(user, "email", email);
DtwResource_set_string_sha_in_sub_resource(user, "password", password);
DtwResource_set_long_in_sub_resource(user, "age", age);
}
int main() {
// Initialize database and schema
DtwResource *database = new_DtwResource("tests/target/schema_database");
DtwDatabaseSchema *root_schema = DtwResource_newDatabaseSchema(database);
DtwSchema *users_schema = DtwDatabaseSchema_new_subSchema(root_schema, "users");
DtwSchema_add_primary_key(users_schema, "name");
DtwSchema_add_primary_key(users_schema, "email");
// Create multiple users
create_users(database, "mateus", "mateusmoutinho01@gmail.com", "1234", 27);
create_users(database, "user1", "user1@gmail.com", "1234", 27);
create_users(database, "user2", "user2@gmail.com", "1234", 27);
// Access users resource
DtwResource *users = DtwResource_sub_resource(database, "users");
// Find and remove a specific user by primary key
DtwResource *mateus = DtwResource_find_by_primary_key_with_string(users, "name", "mateus");
DtwResource_destroy(mateus);
// Error handling
if (DtwResource_error(database)) {
printf("Error: %s\n", DtwResource_get_error_message(database));
DtwResource_free(database);
return 0;
}
// Commit changes and cleanup
DtwResource_commit(database);
DtwResource_free(database);
return 0;
}
Explanation
- Helper Function:
create_userssimplifies the process of adding multiple users. - Removal: The
DtwResource_destroyfunction removes the specified user insertion and associated indices. - Primary Key Search: The user is located using a primary key search before removal.
Finding an Insertion
Using primary keys, you can quickly find a specific insertion without iterating over all records, improving both readability and performance.
Example: Finding a User by Primary Key
#include "doTheWorldOne.c"
// Helper function to create user insertions
void create_users(DtwResource *database, const char *name, const char *email, const char *password, int age) {
DtwResource *users = DtwResource_sub_resource(database, "users");
DtwResource *user = DtwResource_new_schema_insertion(users);
DtwResource_set_string_in_sub_resource(user, "name", name);
DtwResource_set_string_in_sub_resource(user, "email", email);
DtwResource_set_string_sha_in_sub_resource(user, "password", password);
DtwResource_set_long_in_sub_resource(user, "age", age);
}
int main() {
// Initialize database and schema
DtwResource *database = new_DtwResource("tests/target/schema_database");
DtwDatabaseSchema *root_schema = DtwResource_newDatabaseSchema(database);
DtwSchema *users_schema = DtwDatabaseSchema_new_subSchema(root_schema, "users");
DtwSchema_add_primary_key(users_schema, "name");
DtwSchema_add_primary_key(users_schema, "email");
// Create multiple users
create_users(database, "mateus", "mateusmoutinho01@gmail.com", "1234", 27);
create_users(database, "user1", "user1@gmail.com", "1234", 27);
create_users(database, "user2", "user2@gmail.com", "1234", 27);
// Access users resource
DtwResource *users = DtwResource_sub_resource(database, "users");
// Find a user by primary key
DtwResource *mateus = DtwResource_find_by_primary_key_with_string(users, "name", "mateus");
// Retrieve field values
char *name = DtwResource_get_string_from_sub_resource(mateus, "name");
char *email = DtwResource_get_string_from_sub_resource(mateus, "email");
long age = DtwResource_get_long_from_sub_resource(mateus, "age");
// Display retrieved data if no errors
if (!DtwResource_error(database)) {
printf("Name: %s\n", name);
printf("Email: %s\n", email);
printf("Age: %ld\n", age);
}
// Error handling
if (DtwResource_error(database)) {
printf("Error: %s\n", DtwResource_get_error_message(database));
DtwResource_free(database);
return 0;
}
// Commit changes and cleanup
DtwResource_commit(database);
DtwResource_free(database);
return 0;
}
Explanation
- Efficient Lookup: The
DtwResource_find_by_primary_key_with_stringfunction allows direct access to a record using a primary key. - Data Retrieval: Field values are retrieved using type-specific getters (e.g.,
get_string,get_long).
Iterating Over Insertions
You can iterate over all insertions in a schema to process or display records. This is useful for generating reports or performing batch operations.
Example: Iterating Over User Insertions
#include "doTheWorldOne.c"
// Helper function to create user insertions
void create_users(DtwResource *database, const char *name, const char *email, const char *password, int age) {
DtwResource *users = DtwResource_sub_resource(database, "users");
DtwResource *user = DtwResource_new_schema_insertion(users);
DtwResource_set_string_in_sub_resource(user, "name", name);
DtwResource_set_string_in_sub_resource(user, "email", email);
DtwResource_set_string_sha_in_sub_resource(user, "password", password);
DtwResource_set_long_in_sub_resource(user, "age", age);
}
int main() {
// Initialize database and schema
DtwResource *database = new_DtwResource("tests/target/schema_database");
DtwDatabaseSchema *root_schema = DtwResource_newDatabaseSchema(database);
DtwSchema *users_schema = DtwDatabaseSchema_new_subSchema(root_schema, "users");
DtwSchema_add_primary_key(users_schema, "name");
DtwSchema_add_primary_key(users_schema, "email");
// Create multiple users
create_users(database, "mateus", "mateusmoutinho01@gmail.com", "1234", 27);
create_users(database, "user1", "user1@gmail.com", "1234", 27);
create_users(database, "user2", "user2@gmail.com", "1234", 27);
// Access users resource
DtwResource *users = DtwResource_sub_resource(database, "users");
// Get all user insertions as an array
DtwResourceArray *all_users = DtwResource_get_schema_values(users);
// Iterate over each user
for (int i = 0; i < all_users->size; i++) {
DtwResource *current = all_users->resources[i];
char *name = DtwResource_get_string_from_sub_resource(current, "name");
char *email = DtwResource_get_string_from_sub_resource(current, "email");
long age = DtwResource_get_long_from_sub_resource(current, "age");
if (!DtwResource_error(database)) {
printf("Name: %s\n", name);
printf("Email: %s\n", email);
printf("Age: %ld\n", age);
}
}
// Error handling
if (DtwResource_error(database)) {
printf("Error: %s\n", DtwResource_get_error_message(database));
DtwResource_free(database);
return 0;
}
// Commit changes and cleanup
DtwResource_commit(database);
DtwResource_free(database);
return 0;
}
Explanation
- Array Retrieval:
DtwResource_get_schema_valuesreturns an array of all insertions in the schema. - Iteration: A loop processes each insertion, extracting and displaying field values.
Best Practices
- Always Handle Errors: Use
DtwResource_errorandDtwResource_get_error_messageto catch and handle errors gracefully. - Commit Changes: Ensure
DtwResource_commitis called to persist changes to the underlying storage. - Free Resources: Use
DtwResource_freeto prevent memory leaks after operations are complete. - Use Primary Keys: Define primary keys for efficient lookups and to enforce uniqueness.
Notes
- This documentation focuses on schema-specific operations. For broader library usage, refer to the main documentation.
- The examples assume the
doTheWorldOne.cheader provides necessary function definitions and dependencies.