Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 73 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -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.
21 changes: 21 additions & 0 deletions c/Makefile
Original file line number Diff line number Diff line change
@@ -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)
89 changes: 89 additions & 0 deletions c/README.md
Original file line number Diff line number Diff line change
@@ -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 <stdio.h>
#include <stdint.h>
#include <stdlib.h>

// 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)
149 changes: 149 additions & 0 deletions c/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>

// 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;
}
Loading