Skip to content

Commit 49e8812

Browse files
committed
Revise and improve the documentation
1 parent 350b782 commit 49e8812

17 files changed

Lines changed: 468 additions & 109 deletions

Makefile

Lines changed: 7 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,6 @@ BUILD_DIR := zig-out
1212
CACHE_DIR := .zig-cache
1313
DOC_SRC := src/lib.zig
1414
DOC_OUT := docs/api/
15-
COVERAGE_DIR := coverage
16-
BINARY_NAME := zodd
17-
BINARY_PATH := $(BUILD_DIR)/bin/$(BINARY_NAME)
18-
TEST_EXECUTABLE := $(BUILD_DIR)/bin/test
19-
PREFIX ?= /usr/local
2015
RELEASE_MODE := ReleaseSmall
2116

2217
# Get all .zig files in the examples directory and extract their stem names
@@ -56,7 +51,7 @@ else
5651
$(ZIG) build run-$(EXAMPLE) $(BUILD_OPTS)
5752
endif
5853

59-
test: ## Run tests
54+
test: ## Run all tests (unit tests and tests in the `tests/` directory)
6055
@echo "Running tests..."
6156
$(ZIG) build test $(BUILD_OPTS) -j$(JOBS) --summary all
6257

@@ -66,7 +61,7 @@ release: ## Build in Release mode
6661

6762
clean: ## Remove docs, build artifacts, and cache directories
6863
@echo "Removing build artifacts, cache, generated docs, and coverage files..."
69-
rm -rf $(BUILD_DIR) $(CACHE_DIR) $(DOC_OUT) *.profraw $(COVERAGE_DIR)
64+
rm -rf $(BUILD_DIR) $(CACHE_DIR) $(DOC_OUT) *.profraw
7065

7166
lint: ## Check code style and formatting of Zig files
7267
@echo "Running code style checks..."
@@ -77,20 +72,12 @@ format: ## Format Zig files
7772
$(ZIG) fmt .
7873

7974
docs: ## Generate API documentation
80-
@echo "Generating documentation from $(DOC_SRC) to $(DOC_OUT)..."
75+
@echo "Generating documentation..."
76+
$(ZIG) build docs
77+
@echo "Copying documentation to $(DOC_OUT)..."
78+
rm -rf $(DOC_OUT)
8179
mkdir -p $(DOC_OUT)
82-
@if $(ZIG) doc --help > /dev/null 2>&1; then \
83-
$(ZIG) doc $(DOC_SRC) --output-dir $(DOC_OUT); \
84-
else \
85-
$(ZIG) test -femit-docs $(DOC_SRC); \
86-
for f in docs/*; do \
87-
base=$$(basename "$$f"); \
88-
if [ "$$base" = "assets" ] || [ "$$base" = "api" ]; then \
89-
continue; \
90-
fi; \
91-
mv "$$f" $(DOC_OUT)/; \
92-
done; \
93-
fi
80+
cp -r $(BUILD_DIR)/docs/* $(DOC_OUT)
9481

9582
docs-serve: ## Serve API documentation locally
9683
@echo "Serving documentation at http://localhost:8000/..."

README.md

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
[![Zig Version](https://img.shields.io/badge/Zig-0.15.2-orange?logo=zig&labelColor=282c34)](https://ziglang.org/download/)
1414
[![Release](https://img.shields.io/github/release/CogitatorTech/zodd.svg?label=release&style=flat&labelColor=282c34&logo=github)](https://github.com/CogitatorTech/zodd/releases/latest)
1515

16-
A small embeddable Datalog engine in pure Zig
16+
A small embeddable Datalog engine in Zig
1717

1818
</div>
1919

@@ -27,7 +27,7 @@ Datalog is a declarative logic programming language that is used in deductive da
2727
It is a subset of [Prolog](https://en.wikipedia.org/wiki/Prolog) programming language and allows you to define things like facts and rules
2828
and then query those facts and rules to derive new information.
2929

30-
Below is a simple Datalog code-snippet that defines a graph and computes the transitive closure (reachability) between nodes:
30+
Below is a simple Datalog code-snippet that defines a graph and computes the transitive closure of that graph:
3131

3232
```prolog
3333
% Facts: a graph (with four nodes and three edges)
@@ -36,8 +36,8 @@ edge(2, 3).
3636
edge(3, 4).
3737
3838
% Rule: transitive closure of the graph
39-
% A transitive closure of a graph is a relation (a set of nodes) that contains all pairs of nodes
40-
% that are reachable from each other.
39+
% A transitive closure of a graph is a relation (a set of nodes) that contains all pairs
40+
% of nodes that are reachable from each other.
4141
reachable(X, Y) :- edge(X, Y).
4242
reachable(X, Z) :- reachable(X, Y), edge(Y, Z).
4343
```
@@ -179,5 +179,6 @@ Zodd is licensed under the MIT License (see [LICENSE](LICENSE)).
179179
### Acknowledgements
180180

181181
* The logo is from [SVG Repo](https://www.svgrepo.com/svg/469003/gravity) with some modifications.
182-
* This project uses the [Minish](https://github.com/CogitatorTech/minish) framework for property-based testing.
183-
* Zodd is inspired and modeled after the [Datafrog](https://github.com/frankmcsherry/blog/blob/master/posts/2018-05-19.md) Datalog engine for Rust 🦀.
182+
* This project uses the [Minish](https://github.com/CogitatorTech/minish) framework for property-based testing and
183+
the [Ordered](https://github.com/CogitatorTech/minish) Zig library.
184+
* Zodd is inspired and modeled after the [Datafrog](https://github.com/frankmcsherry/blog/blob/master/posts/2018-05-19.md) Datalog engine for Rust.

ROADMAP.md

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,34 +8,34 @@ This document outlines the features implemented in Zodd and the future goals for
88
### Core Features
99

1010
- [x] `Relation` - sorted, deduplicated tuple collections
11-
- [x] `Variable` - incremental update lifecycle (stable/recent/to_add)
11+
- [x] `Variable` - incremental update lifecycle
1212
- [x] `Iteration` - fixed-point computation context
1313
- [x] `gallop` - exponential and binary search for filtering
1414
- [x] `joinHelper` - merge-join on key-value tuples
1515
- [x] `joinInto` - high-level join between variables
16-
- [x] Treefrog Leapjoin interface (`Leaper`)
16+
- [x] `Leaper` - Treefrog Leapjoin interface
1717
- [x] `ExtendWith` - propose values from a relation
1818
- [x] `FilterAnti` - negation (filter out matching tuples)
1919
- [x] `ExtendAnti` - set difference (propose non-matching values)
2020

21-
### Testing
21+
### Extra Features
2222

23-
- [x] Unit tests in each module
24-
- [x] Integration, regression, and property-based tests in `tests` directory
25-
26-
### Extensions
27-
28-
- [ ] Stratified negation
29-
- [x] Aggregation
23+
- [x] Stratified negation
24+
- [x] Aggregations
3025
- [x] Recursion limits
31-
- [ ] Rule DSL
3226
- [x] Persistence
33-
- [ ] Secondary indices
34-
- [ ] Incremental maintenance
35-
- [ ] Query planner
27+
- [x] Secondary indices
28+
- [x] Incremental maintenance
3629
- [ ] Parallel execution
3730
- [ ] CLI interface
38-
- [ ] Magic sets
39-
- [ ] Benchmarks
4031
- [ ] WASM support
4132
- [ ] Streaming input
33+
- [ ] Rule DSL
34+
- [ ] Query planner
35+
- [ ] Magic sets
36+
37+
### Development and Testing
38+
39+
- [x] Unit tests in each module
40+
- [x] Integration, regression, property-based tests, etc. in `tests` directory
41+
- [ ] Benchmarks

build.zig

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,13 @@ pub fn build(b: *std.Build) void {
1111
.optimize = optimize,
1212
});
1313

14+
// Add Ordered dependency to zodd module
15+
const ordered_dep = b.dependency("ordered", .{
16+
.target = target,
17+
.optimize = optimize,
18+
});
19+
zodd_mod.addImport("ordered", ordered_dep.module("ordered"));
20+
1421
// Static library artifact
1522
const lib = b.addLibrary(.{
1623
.name = "zodd",
@@ -32,7 +39,7 @@ pub fn build(b: *std.Build) void {
3239
// Discover and add tests from tests/ directory
3340
// (only available when developing zodd, not when used as a dependency)
3441
if (std.fs.cwd().openDir("tests", .{ .iterate = true })) |tests_dir| {
35-
// Lazy-load minish dependency (only needed for property tests)
42+
// Lazy-load Minish dependency (only needed for property tests)
3643
const minish_dep = b.dependency("minish", .{
3744
.target = target,
3845
.optimize = optimize,
@@ -104,13 +111,18 @@ pub fn build(b: *std.Build) void {
104111
} else |_| {}
105112

106113
// API Documentation
107-
const doc_step = b.step("docs", "Generate API documentation");
108-
const doc_cmd = b.addSystemCommand(&[_][]const u8{
109-
b.graph.zig_exe,
110-
"build-lib",
111-
"src/lib.zig",
112-
"-femit-docs=docs/api",
113-
"-fno-emit-bin",
114+
const docs_step = b.step("docs", "Generate API documentation");
115+
116+
const doc_obj = b.addObject(.{
117+
.name = "zodd",
118+
.root_module = zodd_mod,
114119
});
115-
doc_step.dependOn(&doc_cmd.step);
120+
121+
const install_docs = b.addInstallDirectory(.{
122+
.source_dir = doc_obj.getEmittedDocs(),
123+
.install_dir = .prefix,
124+
.install_subdir = "docs",
125+
});
126+
127+
docs_step.dependOn(&install_docs.step);
116128
}

docs/assets/.gitkeep

Whitespace-only changes.

examples/README.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@
22

33
#### List of Examples
44

5-
| # | File | Description |
6-
|---|--------------------------------------------------------|-----------------------------------------------------------------------------------------------|
7-
| 1 | [e1_transitive_closure.zig](e1_transitive_closure.zig) | Computes the transitive closure of a directed graph using Datalog rules. |
8-
| 2 | [e2_same_generation.zig](e2_same_generation.zig) | Finds all pairs of nodes at the same depth in a hierarchy (siblings, cousins). |
9-
| 3 | [e3_points_to_analysis.zig](e3_points_to_analysis.zig) | Performs points-to analysis for program analysis (alloc, assign, load, and store operations). |
5+
| # | File | Description |
6+
|---|--------------------------------------------------------|--------------------------------------------------------------------------|
7+
| 1 | [e1_transitive_closure.zig](e1_transitive_closure.zig) | Computes the transitive closure of a directed graph using Datalog rules. |
8+
| 2 | [e2_same_generation.zig](e2_same_generation.zig) | Finds all pairs of nodes at the same depth in a hierarchy. |
9+
| 3 | [e3_points_to_analysis.zig](e3_points_to_analysis.zig) | Performs points-to analysis for a program. |
1010

1111
#### Running Examples
1212

src/lib.zig

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
1+
//! Zodd: A small embeddable Datalog engine for Zig.
2+
13
pub const relation = @import("zodd/relation.zig");
24
pub const variable = @import("zodd/variable.zig");
35
pub const iteration = @import("zodd/iteration.zig");
46
pub const join = @import("zodd/join.zig");
57
pub const extend = @import("zodd/extend.zig");
68

9+
pub const index = @import("zodd/indexing.zig");
710
pub const aggregate = @import("zodd/aggregate.zig");
811

912
pub const Relation = relation.Relation;
@@ -12,6 +15,7 @@ pub const gallop = variable.gallop;
1215
pub const Iteration = iteration.Iteration;
1316
pub const joinHelper = join.joinHelper;
1417
pub const joinInto = join.joinInto;
18+
pub const joinAnti = join.joinAnti;
1519
pub const Leaper = extend.Leaper;
1620
pub const ExtendWith = extend.ExtendWith;
1721
pub const FilterAnti = extend.FilterAnti;

src/zodd/aggregate.zig

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
//! Group-by and aggregation primitives for relations.
2+
13
const std = @import("std");
24
const Allocator = std.mem.Allocator;
35
const Relation = @import("relation.zig").Relation;
@@ -18,13 +20,6 @@ pub fn aggregate(
1820
return Relation(ResultTuple).empty(allocator);
1921
}
2022

21-
// Since input is sorted by Tuple, but we might be grouping by arbitrary Key,
22-
// the input might NOT be sorted by Key.
23-
// If Key is a prefix of Tuple, it IS sorted by Key.
24-
// Optimization: check if Key is prefix? For now, let's assume worst case and use a hash map or sort.
25-
// Actually, sorting a persistent array is better than hash map for memory locality usually.
26-
27-
// Let's create an array of (Key, Val) and sort it by Key.
2823
const Intermediate = struct { Key, *const Tuple };
2924
var intermediates = try allocator.alloc(Intermediate, input.len());
3025
defer allocator.free(intermediates);
@@ -49,14 +44,12 @@ pub fn aggregate(
4944

5045
for (intermediates) |item| {
5146
if (std.math.order(item[0], current_key) != .eq) {
52-
// finish previous group
5347
try results.append(allocator, .{ current_key, current_acc });
5448
current_key = item[0];
5549
current_acc = init_val;
5650
}
5751
current_acc = folder(current_acc, item[1]);
5852
}
59-
// finish last group
6053
try results.append(allocator, .{ current_key, current_acc });
6154
}
6255

@@ -65,7 +58,7 @@ pub fn aggregate(
6558

6659
test "aggregate: sum by key" {
6760
const allocator = std.testing.allocator;
68-
const Tuple = struct { u32, u32 }; // id, value
61+
const Tuple = struct { u32, u32 };
6962

7063
var data = try Relation(Tuple).fromSlice(allocator, &[_]Tuple{
7164
.{ 1, 10 },

0 commit comments

Comments
 (0)