2026-05-21 16:16:14 +02:00
|
|
|
# Storage engine playground helpers.
|
2026-05-21 12:28:09 +02:00
|
|
|
|
2026-05-21 16:16:14 +02:00
|
|
|
HAS_CARGO := $(wildcard Cargo.toml)
|
2026-05-21 12:28:09 +02:00
|
|
|
|
2026-05-29 15:22:47 +02:00
|
|
|
# Workspace crates discovered under `crates/*/Cargo.toml`. The directory name is
|
|
|
|
|
# assumed to match the package name (the convention documented in crates/README.md).
|
|
|
|
|
CRATE_MANIFESTS := $(wildcard crates/*/Cargo.toml)
|
|
|
|
|
CRATES := $(patsubst crates/%/Cargo.toml,%,$(CRATE_MANIFESTS))
|
|
|
|
|
CRATE_FLAGS := $(addprefix -p ,$(CRATES))
|
|
|
|
|
|
2026-05-21 12:28:09 +02:00
|
|
|
.DEFAULT_GOAL := help
|
|
|
|
|
|
|
|
|
|
.PHONY: help
|
|
|
|
|
help: ## Show help messages for all available targets
|
|
|
|
|
@grep -E '^[a-zA-Z_-]+:.*## .*$$' Makefile | \
|
|
|
|
|
awk 'BEGIN {FS = ":.*## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}'
|
|
|
|
|
|
2026-05-29 15:06:44 +02:00
|
|
|
.PHONY: format
|
|
|
|
|
format: ## Apply code formatting
|
2026-05-21 16:16:14 +02:00
|
|
|
@if [ -z "$(HAS_CARGO)" ]; then \
|
|
|
|
|
echo "No Cargo.toml found. Skipping Rust formatting."; \
|
|
|
|
|
else \
|
|
|
|
|
cargo fmt --all; \
|
|
|
|
|
fi
|
2026-05-21 12:28:09 +02:00
|
|
|
|
2026-05-29 15:06:44 +02:00
|
|
|
.PHONY: format-check
|
|
|
|
|
format-check: ## Check code formatting without applying changes
|
2026-05-21 16:16:14 +02:00
|
|
|
@if [ -z "$(HAS_CARGO)" ]; then \
|
|
|
|
|
echo "No Cargo.toml found. Skipping Rust format check."; \
|
|
|
|
|
else \
|
|
|
|
|
cargo fmt --all --check; \
|
|
|
|
|
fi
|
2026-05-21 12:28:09 +02:00
|
|
|
|
2026-05-29 15:06:44 +02:00
|
|
|
.PHONY: lint
|
2026-05-29 15:22:47 +02:00
|
|
|
lint: ## Run linters across every crate under crates/
|
2026-05-21 16:16:14 +02:00
|
|
|
@if [ -z "$(HAS_CARGO)" ]; then \
|
2026-05-29 15:06:44 +02:00
|
|
|
echo "No Cargo.toml found. Skipping lint."; \
|
2026-05-29 15:22:47 +02:00
|
|
|
elif [ -z "$(CRATES)" ]; then \
|
|
|
|
|
echo "No crates/*/Cargo.toml found. Skipping lint."; \
|
2026-05-21 16:16:14 +02:00
|
|
|
else \
|
2026-05-29 15:22:47 +02:00
|
|
|
cargo clippy $(CRATE_FLAGS) --no-deps -- -D warnings -D clippy::unwrap_used -D clippy::expect_used; \
|
2026-05-21 16:16:14 +02:00
|
|
|
fi
|
2026-05-21 12:28:09 +02:00
|
|
|
|
2026-05-21 16:16:14 +02:00
|
|
|
.PHONY: test
|
2026-06-04 12:47:47 +02:00
|
|
|
test: ## Run unit, integration, and doc tests across all features (no benches)
|
2026-05-21 16:16:14 +02:00
|
|
|
@if [ -z "$(HAS_CARGO)" ]; then \
|
2026-05-29 15:06:44 +02:00
|
|
|
echo "No Cargo.toml found. Skipping tests."; \
|
2026-05-21 16:16:14 +02:00
|
|
|
else \
|
2026-06-04 12:47:47 +02:00
|
|
|
cargo test --all-features; \
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
.PHONY: bench
|
|
|
|
|
bench: ## Run benchmarks across all features
|
|
|
|
|
@if [ -z "$(HAS_CARGO)" ]; then \
|
|
|
|
|
echo "No Cargo.toml found. Skipping benchmarks."; \
|
|
|
|
|
else \
|
|
|
|
|
cargo bench --all-features; \
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
.PHONY: bench-check
|
|
|
|
|
bench-check: ## Type-check benchmark code without running it
|
|
|
|
|
@if [ -z "$(HAS_CARGO)" ]; then \
|
|
|
|
|
echo "No Cargo.toml found. Skipping bench check."; \
|
|
|
|
|
else \
|
|
|
|
|
cargo check --benches --all-features --quiet; \
|
2026-05-21 16:16:14 +02:00
|
|
|
fi
|
2026-05-21 12:28:09 +02:00
|
|
|
|
|
|
|
|
.PHONY: check
|
2026-06-11 17:14:29 +02:00
|
|
|
check: format-check lint test bench-check viewer-test ## Run all checks (format-check, lint, test, bench-check, viewer-test)
|
2026-05-21 12:28:09 +02:00
|
|
|
|
|
|
|
|
.PHONY: clean
|
2026-05-21 16:16:14 +02:00
|
|
|
clean: ## Remove build output
|
|
|
|
|
@if [ -z "$(HAS_CARGO)" ]; then \
|
|
|
|
|
echo "No Cargo.toml found. Nothing to clean."; \
|
|
|
|
|
else \
|
|
|
|
|
cargo clean; \
|
|
|
|
|
fi
|
2026-05-21 12:28:09 +02:00
|
|
|
|
2026-06-05 11:20:50 +02:00
|
|
|
EXPORTER_DIR := tools/exporter
|
2026-06-05 11:31:18 +02:00
|
|
|
EXPORTER_FIXTURES := crates/plan-runner/fixtures
|
|
|
|
|
EXAMPLES_DIR := $(EXPORTER_DIR)/examples
|
2026-06-05 11:20:50 +02:00
|
|
|
|
|
|
|
|
.PHONY: export-fixtures
|
2026-06-05 11:31:18 +02:00
|
|
|
export-fixtures: ## Regenerate plan JSON for every tools/exporter/examples/*.scenario.json (needs Cabal and GHC; use `make shell` first).
|
2026-06-05 11:20:50 +02:00
|
|
|
@if ! command -v cabal >/dev/null 2>&1; then \
|
|
|
|
|
echo "cabal not found. Enter the dev shell with 'make shell' (or 'nix develop') first."; \
|
|
|
|
|
exit 1; \
|
|
|
|
|
fi
|
2026-06-05 11:31:18 +02:00
|
|
|
@cd $(EXPORTER_DIR) && cabal build plan-export
|
|
|
|
|
@mkdir -p $(EXPORTER_FIXTURES)
|
|
|
|
|
@for sc in $(EXAMPLES_DIR)/*.scenario.json; do \
|
|
|
|
|
base=$$(basename $$sc .scenario.json); \
|
|
|
|
|
out=$(EXPORTER_FIXTURES)/$$base.json; \
|
2026-06-05 11:20:50 +02:00
|
|
|
echo "exporting $$sc -> $$out"; \
|
2026-06-05 11:31:18 +02:00
|
|
|
(cd $(EXPORTER_DIR) && cabal run -v0 plan-export -- examples/$$base.scenario.json) > $$out; \
|
2026-06-05 11:20:50 +02:00
|
|
|
done
|
|
|
|
|
|
2026-06-05 11:31:18 +02:00
|
|
|
.PHONY: examples
|
|
|
|
|
examples: export-fixtures ## Regenerate fixtures from scenarios and run them through plan-runner against their oracles.
|
|
|
|
|
@cargo test -p plan-runner --test examples
|
|
|
|
|
|
2026-06-15 15:32:57 +02:00
|
|
|
DEMO_SCENARIO ?= two_atom_join
|
|
|
|
|
|
|
|
|
|
.PHONY: demo
|
|
|
|
|
demo: ## Run the end-to-end demo: query -> geolog plan -> Geomerge storage -> execution -> verified results
|
|
|
|
|
@if [ -z "$(HAS_CARGO)" ]; then \
|
|
|
|
|
echo "No Cargo.toml found. Skipping demo."; \
|
|
|
|
|
exit 1; \
|
|
|
|
|
fi
|
|
|
|
|
@echo "=== End-to-end demo: query -> plan -> Geomerge -> results ==="
|
|
|
|
|
@echo ""
|
|
|
|
|
@python3 -c 'import json, sys; \
|
|
|
|
|
s = json.load(open(sys.argv[1])); \
|
|
|
|
|
arity = lambda t: len(s["schema"][t]["columns"]); \
|
|
|
|
|
term = lambda a, i: a["values"].get(str(i), {}).get("var", "_"); \
|
|
|
|
|
atoms = ", ".join(a["table"] + "(" + ", ".join(term(a, i) for i in range(arity(a["table"]))) + ")" for a in s["atoms"]); \
|
|
|
|
|
print("query (" + sys.argv[1] + "):"); \
|
|
|
|
|
print(" " + atoms)' tools/exporter/examples/$(DEMO_SCENARIO).scenario.json
|
|
|
|
|
@echo ""
|
|
|
|
|
@echo "The committed plan below was produced from this query by the geolog"
|
|
|
|
|
@echo "planner via tools/exporter (make export-fixtures regenerates it)."
|
|
|
|
|
@echo ""
|
|
|
|
|
@result=$$(cargo run -q -p plan-runner -- --trace --backend geomerge crates/plan-runner/fixtures/$(DEMO_SCENARIO).json); \
|
|
|
|
|
echo ""; \
|
|
|
|
|
echo "result bindings:"; \
|
|
|
|
|
echo "$$result" | python3 -m json.tool --indent 2
|
|
|
|
|
@echo ""
|
|
|
|
|
@echo "Inspect the plan visually: run 'make viewer' and open"
|
|
|
|
|
@echo " http://localhost:$(VIEWER_PORT)/tools/plan-viewer/index.html?fixture=../../crates/plan-runner/fixtures/$(DEMO_SCENARIO).json"
|
|
|
|
|
|
2026-06-11 17:14:29 +02:00
|
|
|
.PHONY: viewer-test
|
|
|
|
|
viewer-test: ## Check the plan viewer's JS engine against every fixture oracle (needs Node)
|
|
|
|
|
@if ! command -v node >/dev/null 2>&1; then \
|
|
|
|
|
echo "node not found. Skipping plan viewer engine check."; \
|
|
|
|
|
else \
|
|
|
|
|
node tools/plan-viewer/test.js; \
|
|
|
|
|
fi
|
|
|
|
|
|
2026-06-11 15:58:24 +02:00
|
|
|
VIEWER_PORT ?= 8000
|
|
|
|
|
|
|
|
|
|
.PHONY: viewer
|
|
|
|
|
viewer: ## Serve the repository over HTTP for the plan viewer (override the port with VIEWER_PORT=...)
|
|
|
|
|
@if ! command -v python3 >/dev/null 2>&1; then \
|
|
|
|
|
echo "python3 not found. Enter the dev shell with 'make shell' (or 'nix develop') first."; \
|
|
|
|
|
exit 1; \
|
|
|
|
|
fi
|
|
|
|
|
@echo "Plan viewer: http://localhost:$(VIEWER_PORT)/tools/plan-viewer/index.html"
|
|
|
|
|
@echo "Example: http://localhost:$(VIEWER_PORT)/tools/plan-viewer/index.html?fixture=../../crates/plan-runner/fixtures/two_atom_join.json"
|
|
|
|
|
@python3 -m http.server $(VIEWER_PORT)
|
|
|
|
|
|
2026-05-29 15:22:47 +02:00
|
|
|
.PHONY: shell
|
|
|
|
|
shell: ## Enter the Nix dev shell defined in flake.nix
|
|
|
|
|
@nix develop
|
|
|
|
|
|
2026-05-21 12:28:09 +02:00
|
|
|
.PHONY: setup-hooks
|
2026-05-21 16:16:14 +02:00
|
|
|
setup-hooks: ## Install Git hooks with pre-commit
|
2026-05-21 12:28:09 +02:00
|
|
|
@pre-commit install --hook-type pre-commit
|
|
|
|
|
@pre-commit install --hook-type pre-push
|
|
|
|
|
@pre-commit install-hooks
|
|
|
|
|
|
|
|
|
|
.PHONY: test-hooks
|
|
|
|
|
test-hooks: ## Run pre-commit hooks across all files
|
|
|
|
|
@pre-commit run --all-files --show-diff-on-failure
|