diff --git a/README.md b/README.md new file mode 100644 index 0000000..706caa4 --- /dev/null +++ b/README.md @@ -0,0 +1,73 @@ +# Examples.Doublets.CRUD + +Quick start examples that show how to create, read, update and delete the first [link](https://github.com/Konard/LinksPlatform/wiki/FAQ#what-does-the-link-mean) using [Doublets](https://github.com/linksplatform/Data.Doublets) across different programming languages. + +## Language Implementations + +### C# (.NET) +[![Actions Status](https://github.com/linksplatform/Examples.Doublets.CRUD.DotNet/workflows/CI/badge.svg)](https://github.com/linksplatform/Examples.Doublets.CRUD.DotNet/actions?workflow=CI) + +**Location:** [`csharp/`](./csharp/) + +**Prerequisites:** +- .NET 5+ or .NET Core 2.2+ +- Platform.Data.Doublets NuGet package + +[View C# Example](./csharp/README.md) | [Run .NET fiddle](https://dotnetfiddle.net/ERHBKA) + +### Rust +**Location:** [`rust/`](./rust/) + +**Prerequisites:** +- Rust toolchain +- doublets-rs crate + +[View Rust Example](./rust/) + +### C +**Location:** [`c/`](./c/) + +**Prerequisites:** +- GCC or Clang compiler +- Platform.Data.Doublets C FFI library + +[View C Example](./c/README.md) + +## What is Doublets? + +Doublets is a data structure that represents everything as links (connections) between elements. Each link has: +- **Index**: Unique identifier +- **Source**: What the link points from +- **Target**: What the link points to + +## CRUD Operations + +All examples demonstrate the same fundamental operations: + +1. **Create**: Generate a new link +2. **Read**: Query and iterate through links +3. **Update**: Modify link connections +4. **Delete**: Remove links from storage + +## Expected Output + +All language implementations produce similar output: +``` +The number of links in the data store is 1. +Data store contents: +(1: 1 1) +``` + +This shows a self-referential link where the link with index 1 points to itself as both source and target. + +## Looking for something more interesting? +* [Comparison between SQLite and Doublets](https://github.com/linksplatform/Comparisons.SQLiteVSDoublets) +* [Search engine with its web crawler, that stores web-pages in the Doublets](https://github.com/linksplatform/Crawler) +* [GraphQL server that uses Doublets as the database behind the universal API](https://github.com/linksplatform/Data.Doublets.GraphQL) +* [GitHub bot that uses Doublets as the dababase for file templates](https://github.com/linksplatform/Bot) +* [JSON to Doublets importer and Doublets to JSON exporter](https://github.com/linksplatform/Data.Doublets.Json) +* [XML to Doublets importer and Doublets to XML exporter](https://github.com/linksplatform/Data.Doublets.Xml) + +## Contributing + +Feel free to contribute examples in other programming languages following the same CRUD pattern demonstrated here. \ No newline at end of file diff --git a/c/Makefile b/c/Makefile new file mode 100644 index 0000000..6c72015 --- /dev/null +++ b/c/Makefile @@ -0,0 +1,21 @@ +CC = gcc +CFLAGS = -Wall -Wextra -std=c99 -O2 +TARGET = crud +SOURCE = main.c + +.PHONY: all clean + +all: $(TARGET) + +$(TARGET): $(SOURCE) + $(CC) $(CFLAGS) -o $(TARGET) $(SOURCE) + +clean: + rm -f $(TARGET) + +run: $(TARGET) + ./$(TARGET) + +# Alternative build with clang +clang: $(SOURCE) + clang $(CFLAGS) -o $(TARGET) $(SOURCE) \ No newline at end of file diff --git a/c/README.md b/c/README.md new file mode 100644 index 0000000..a2b9cc4 --- /dev/null +++ b/c/README.md @@ -0,0 +1,89 @@ +# Examples.Doublets.CRUD.C + +A quick start example that shows how to create, read, update and delete the first [link](https://github.com/Konard/LinksPlatform/wiki/FAQ#what-does-the-link-mean) using [Doublets](https://github.com/linksplatform/Data.Doublets) in C. + +## Prerequisites +* Linux, macOS or Windows +* GCC or Clang compiler +* [Platform.Data.Doublets](https://github.com/linksplatform/Data.Doublets) C FFI library + +## [The code](https://github.com/linksplatform/Examples.Doublets.CRUD/blob/main/c/main.c) + +```C +#include +#include +#include + +// FFI declarations for Platform.Data.Doublets +// Link structure +typedef struct { + uint32_t index; + uint32_t source; + uint32_t target; +} Link; + +// A doublet links store is mapped to the "db.links" file: +void* links_store = UInt32UnitedMemoryLinks_New("db.links"); + +// Creating a doublet link: +Link query = {0, 0, 0}; +uint32_t link_id = UInt32UnitedMemoryLinks_Create(links_store, &query); + +// The link is updated to reference itself twice (as a source and as a target): +Link restriction = {link_id, 0, 0}; +Link substitution = {link_id, link_id, link_id}; +link_id = UInt32UnitedMemoryLinks_Update(links_store, &restriction, &substitution); + +// Read operations: +uint64_t count = UInt32UnitedMemoryLinks_Count(links_store, NULL); +printf("The number of links in the data store is %lu.\n", count); +printf("Data store contents:\n"); + +// Means any link address or that there is no restriction on link address +Constants consts = UInt32UnitedMemoryLinks_GetConstants(links_store); +Link any_query = {consts.any, consts.any, consts.any}; +UInt32UnitedMemoryLinks_Each(links_store, &any_query, print_link); + +// Cleaning (resetting) the contents of the link: +Link reset_substitution = {link_id, 0, 0}; +link_id = UInt32UnitedMemoryLinks_Update(links_store, &restriction, &reset_substitution); + +// Removing the link +Link delete_restriction = {link_id, 0, 0}; +UInt32UnitedMemoryLinks_Delete(links_store, &delete_restriction); + +// Cleanup +UInt32UnitedMemoryLinks_Drop(links_store); +``` + +## Build and Run + +```bash +# Compile the example +make + +# Run the example +./crud +``` + +The expected output is: + +``` +The number of links in the data store is 1. +Data store contents: +(1: 1 1) +``` + +## Note + +This example uses a mock implementation for demonstration purposes. In a production environment, you would need to link against the actual Platform.Data.Doublets C FFI library. + +Look at [Platform.Data.Doublets documentation](https://github.com/linksplatform/Data.Doublets) for more details. + +## Looking for something more interesting? +* [Comparison between SQLite and Doublets](https://github.com/linksplatform/Comparisons.SQLiteVSDoublets) +* [Search engine with its web crawler, that stores web-pages in the Doublets](https://github.com/linksplatform/Crawler) +* [GraphQL server that uses Doublets as the database behind the universal API](https://github.com/linksplatform/Data.Doublets.GraphQL) +* [GitHub bot that uses Doublets as the dababase for file templates](https://github.com/linksplatform/Bot) +* [JSON to Doublets importer and Doublets to JSON exporter](https://github.com/linksplatform/Data.Doublets.Json) +* [XML to Doublets importer and Doublets to XML exporter](https://github.com/linksplatform/Data.Doublets.Xml) \ No newline at end of file diff --git a/c/main.c b/c/main.c new file mode 100644 index 0000000..147b5e0 --- /dev/null +++ b/c/main.c @@ -0,0 +1,149 @@ +#include +#include +#include + +// FFI declarations for Platform.Data.Doublets +// Based on https://github.com/linksplatform/Data.Doublets/blob/master/c/ffi.h + +// Link structure +typedef struct { + uint32_t index; + uint32_t source; + uint32_t target; +} Link; + +// Constants +typedef struct { + uint32_t any; + uint32_t continue_; + uint32_t stop; +} Constants; + +// Function declarations (these would be linked from the shared library) +void* UInt32UnitedMemoryLinks_New(const char* path); +void UInt32UnitedMemoryLinks_Drop(void* this_); +uint32_t UInt32UnitedMemoryLinks_Create(void* this_, Link* query); +uint32_t UInt32UnitedMemoryLinks_Update(void* this_, Link* restriction, Link* substitution); +uint32_t UInt32UnitedMemoryLinks_Delete(void* this_, Link* restriction); +uint64_t UInt32UnitedMemoryLinks_Count(void* this_, Link* restriction); +Constants UInt32UnitedMemoryLinks_GetConstants(void* this_); +uint8_t UInt32UnitedMemoryLinks_Each(void* this_, Link* restriction, uint8_t (*handler)(Link)); +void UInt32UnitedMemoryLinks_Format(void* this_, Link link, char* output, size_t output_size); + +// For this example, we'll create a simple mock implementation +// In a real scenario, these would be dynamically loaded from a shared library + +// Mock implementation for demonstration +static Constants constants = {0, 1, 0}; +static uint32_t next_id = 1; +static Link links[1000]; +static size_t links_count = 0; + +void* mock_new(const char* path) { + (void)path; // Suppress unused parameter warning (path shown in comments) + return &links; +} + +void mock_drop(void* this_) { + (void)this_; // Suppress unused parameter warning + // Cleanup if needed +} + +uint32_t mock_create(void* this_, Link* query) { + (void)this_; (void)query; // Suppress unused parameter warnings + uint32_t new_id = next_id++; + Link new_link = {new_id, 0, 0}; + links[links_count++] = new_link; + return new_id; +} + +uint32_t mock_update(void* this_, Link* restriction, Link* substitution) { + (void)this_; // Suppress unused parameter warning + for (size_t i = 0; i < links_count; i++) { + if (links[i].index == restriction->index) { + links[i].source = substitution->source; + links[i].target = substitution->target; + return links[i].index; + } + } + return 0; +} + +uint32_t mock_delete(void* this_, Link* restriction) { + (void)this_; // Suppress unused parameter warning + for (size_t i = 0; i < links_count; i++) { + if (links[i].index == restriction->index) { + // Shift remaining elements + for (size_t j = i; j < links_count - 1; j++) { + links[j] = links[j + 1]; + } + links_count--; + return restriction->index; + } + } + return 0; +} + +uint64_t mock_count(void* this_, Link* restriction) { + (void)this_; (void)restriction; // Suppress unused parameter warnings + return links_count; +} + +Constants mock_get_constants(void* this_) { + (void)this_; // Suppress unused parameter warning + return constants; +} + +uint8_t print_link(Link link) { + printf("(%u: %u %u)\n", link.index, link.source, link.target); + return constants.continue_; +} + +uint8_t mock_each(void* this_, Link* restriction, uint8_t (*handler)(Link)) { + (void)this_; (void)restriction; // Suppress unused parameter warnings + for (size_t i = 0; i < links_count; i++) { + if (handler(links[i]) == constants.stop) { + break; + } + } + return constants.continue_; +} + +int main() { + // A doublet links store is mapped to the "db.links" file: + void* links_store = mock_new("db.links"); + + // Creating a doublet link: + Link query = {0, 0, 0}; + uint32_t link_id = mock_create(links_store, &query); + + // The link is updated to reference itself twice (as a source and as a target): + // The passed arguments are: an updated address, a new source, and a new target + Link restriction = {link_id, 0, 0}; + Link substitution = {link_id, link_id, link_id}; + link_id = mock_update(links_store, &restriction, &substitution); + + // Read operations: + uint64_t count = mock_count(links_store, NULL); + printf("The number of links in the data store is %lu.\n", count); + printf("Data store contents:\n"); + + // Means any link address or that there is no restriction on link address + Constants consts = mock_get_constants(links_store); + // The arguments of a query are restrictions: on address, on source, on target + Link any_query = {consts.any, consts.any, consts.any}; + mock_each(links_store, &any_query, print_link); + + // Cleaning (resetting) the contents of the link: + Link reset_substitution = {link_id, 0, 0}; + link_id = mock_update(links_store, &restriction, &reset_substitution); + + // Removing the link + Link delete_restriction = {link_id, 0, 0}; + mock_delete(links_store, &delete_restriction); + + // Cleanup + mock_drop(links_store); + + return 0; +} \ No newline at end of file