Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
c64d614
add ephemeral relations on the top of the query planner
MMagueta Dec 4, 2025
f76443b
grouped provenance
MMagueta Dec 4, 2025
e1801a8
remove legacy function no one cares about
MMagueta Dec 7, 2025
9479a19
provenance oonly at the top level
MMagueta Dec 7, 2025
fa18c65
fix relational operators and separate them into another module
MMagueta Dec 7, 2025
60c41b3
fix finite relation generators based on functions on tuple iterators
MMagueta Dec 7, 2025
cf4d286
refactor: code simplification and quality improvements
MMagueta Dec 7, 2025
e84a454
purge scan in favor of relation name and fix hash retrieval from planner
MMagueta Dec 7, 2025
e52d6ac
clean tests
MMagueta Dec 7, 2025
627f835
fix loops and rename dummy create tuple all
MMagueta Dec 8, 2025
3ee3b0a
refactor operations
MMagueta Dec 8, 2025
b1f8b07
port setup to main on startup
MMagueta Dec 9, 2025
cc09d9d
rework simplify generators for pure relations as funs
MMagueta Dec 9, 2025
c98813b
update tests and clean planner
MMagueta Dec 9, 2025
0457740
add back list of relations for relation-explorer
MMagueta Dec 9, 2025
63563a8
infinite domains now generated with unified API with spawns
MMagueta Dec 9, 2025
f36344b
remove prefix join test
MMagueta Dec 9, 2025
d826d9d
remove mutable and rename immutable relation spec to domain
MMagueta Dec 13, 2025
c5b4505
remove mutability from relational operations
MMagueta Dec 13, 2025
edfc774
delete tests bloat
MMagueta Dec 13, 2025
811fde4
exclude test module from dialyzer
MMagueta Dec 13, 2025
edc3e25
delete operations tests
MMagueta Dec 13, 2025
5b2d9ab
fix dialyzer deps
MMagueta Dec 14, 2025
534ed20
wip new uuid_erl dep without sha
MMagueta Dec 14, 2025
7c4c437
add incorrect sha
MMagueta Dec 14, 2025
4ddc44d
add correct sha for uuid_erl
MMagueta Dec 14, 2025
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
.direnv
_build
Mnesia.*

Expand Down
24 changes: 3 additions & 21 deletions include/operations.hrl
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,15 @@
cardinality, % {finite, N} | aleph_zero | continuum
generator, % Generator function (immutable only), undefined for tree-based
membership_criteria, % #{attribute_name => constraint_spec()} - domain membership test
mutability, % mutable | immutable
provenance % Provenance tracking for updatable views (future)
provenance, % attribute_provenance() - maps attribute to source relation
lineage % lineage_op() - operation tree showing derivation
}).

-record(tuple, {hash, relation, attribute_map}).
-record(attribute, {hash, value}).

%% Specification record for creating immutable relations
-record(immutable_relation_spec, {
-record(domain, {
name, % Atom - relation name
schema, % #{attribute_name => relation_name}
generator, % {module, function} - tuple generator
Expand All @@ -33,11 +33,6 @@
| aleph_zero % Countably infinite (ℵ₀)
| continuum. % Uncountably infinite (2^ℵ₀)

%%% Mutability Types

-type mutability() :: mutable % Supports insert/delete (tree-based)
| immutable. % Read-only (generator-based or protected)

%%% Constraint Types

-type constraint_spec() ::
Expand Down Expand Up @@ -108,16 +103,3 @@
| {take, pos_integer(), lineage_op()} % Limit operation
| {aggregate, atom(), atom(), lineage_op()}. % Aggregation (future)

%% Tuple metadata (contains provenance, lineage, and other system-managed fields)
-type tuple_metadata() :: #{
provenance => attribute_provenance(),
lineage => lineage_op()
% Future: timestamp, version, etc.
}.

%% Tuples with metadata use a nested 'meta' field:
%% #{id => 1, name => "Alice",
%% meta => #{
%% provenance => #{id => {employees, id}, name => {employees, name}},
%% lineage => {select, fun(T) -> maps:get(age, T) > 30 end, {base, employees}}
%% }}
10 changes: 10 additions & 0 deletions rebar-deps.nix
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,15 @@ let
};
beamDeps = [ ];
};
uuid_erl = builder {
name = "uuid_erl";
version = "2.0.7";
src = fetchHex {
pkg = "uuid_erl";
version = "2.0.7";
sha256 = "sha256-Tkxco0YdxHxeFX7UKqOYGgU7ehhnkq+XKiexSpSJMk4=";
};
beamDeps = [ ];
};
};
in self
19 changes: 7 additions & 12 deletions rebar.config
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@

%% == Dependencies and Plugins ==
{deps, [
{merklet, "2.0.0"}]
}.
{merklet, "2.0.0"},
{uuid_erl, "2.0.7"}
]}.

{plugins, [
{covertool, "2.0.7"},
Expand All @@ -23,7 +24,8 @@
%% == Releases ==
{relx, [
{release, {domino, "0.1.0"}, [
merklet
merklet,
uuid_erl
]},

{mode, dev},
Expand Down Expand Up @@ -80,17 +82,10 @@

%% == Dialyzer Settings ==
{dialyzer, [
{plt_extra_apps, [merklet]},
{plt_extra_apps, [merklet, uuid_erl, quickrand]},
{warnings, [unknown]},
{exclude_mods, [
query_planner_test,
repl_comprehensive_test,
function_relations_test,
infinite_relations_test,
join_test,
operations_test,
provenance_test,
query_pipeline_test

]}
]}.

Expand Down
12 changes: 9 additions & 3 deletions rebar.lock
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
{"1.2.0",
[{<<"merklet">>,{pkg,<<"merklet">>,<<"2.0.0">>},0}]}.
[{<<"merklet">>,{pkg,<<"merklet">>,<<"2.0.0">>},0},
{<<"quickrand">>,{pkg,<<"quickrand">>,<<"2.0.7">>},1},
{<<"uuid_erl">>,{pkg,<<"uuid_erl">>,<<"2.0.7">>},0}]}.
[
{pkg_hash,[
{<<"merklet">>, <<"9E53AA5F83B4CE33A8EE0BEDC798AA54A1750A8FD92D649FC04BA7F7B8E65E78">>}]},
{<<"merklet">>, <<"9E53AA5F83B4CE33A8EE0BEDC798AA54A1750A8FD92D649FC04BA7F7B8E65E78">>},
{<<"quickrand">>, <<"D2BD76676A446E6A058D678444B7FDA1387B813710D1AF6D6E29BB92186C8820">>},
{<<"uuid_erl">>, <<"B2078D2CC814F53AFA52D36C91E08962C7E7373585C623F4C0EA6DFB04B2AF94">>}]},
{pkg_hash_ext,[
{<<"merklet">>, <<"B5E868DA5979F9B3C3E4E8B8171AA5C167868E35495B81731C93D8382FDD3278">>}]}
{<<"merklet">>, <<"B5E868DA5979F9B3C3E4E8B8171AA5C167868E35495B81731C93D8382FDD3278">>},
{<<"quickrand">>, <<"B8ACBF89A224BC217C3070CA8BEBC6EB236DBE7F9767993B274084EA044D35F0">>},
{<<"uuid_erl">>, <<"4E4C5CA3461DC47C5E157ED42AA3981A053B7A186792AF972A27B14A9489324E">>}]}
].
60 changes: 50 additions & 10 deletions src/main.erl
Original file line number Diff line number Diff line change
@@ -1,26 +1,66 @@
-module(main).
-behaviour(application).

-export([start/2, stop/1]).
-export([start/2, stop/1, setup/0]).

%% @doc Initialize Mnesia database schema and tables.
%%
%% Creates a fresh Mnesia schema with four tables for content-addressed storage:
%% <ul>
%% <li>`attribute' - Hash → Value mapping for deduplication</li>
%% <li>`tuple' - Hash → Tuple mapping with attribute references</li>
%% <li>`relation' - Hash → Relation with merkle tree and schema</li>
%% <li>`database_state' - Hash → Database with relation merkle tree</li>
%% </ul>
%%
%% <b>Warning:</b> This function deletes any existing schema and recreates it from scratch.
%%
%% @returns `ok' on success
%% @see operations:create_database/1
setup() ->
mnesia:stop(),
mnesia:delete_schema([node()]),
mnesia:create_schema([node()]),
mnesia:start(),
mnesia:create_table(attribute, [
{attributes, [hash, value]},
{disc_copies, [node()]},
{type, set}
]),
mnesia:create_table(tuple, [
{attributes, [hash, relation, attribute_map]},
{disc_copies, [node()]},
{type, set}
]),
mnesia:create_table(relation, [
{attributes, [hash, name, tree, schema, constraints, cardinality, generator, membership_criteria, mutability, provenance, lineage]},
{disc_copies, [node()]},
{type, set},
{index, [name]} % Index on name for efficient lookup
]),
mnesia:create_table(database_state, [
{attributes, [hash, name, tree, relations, timestamp]},
{disc_copies, [node()]},
{type, set}
]).

uuid() ->
ok = application:load(quickrand),
ok = quickrand:seed(),
ok = quickrand_cache:init(),
quickrand_cache:new().

start(_StartType, _StartArgs) ->
%% Start Mnesia (or other children) here
io:format("Starting app...~n"),

%% Ensure Mnesia is started
mnesia:start(),
setup(),
_ = uuid(),

{ok, self()}.

stop(_State) ->
io:format("Stopping app...~n"),
ok.

%% setup() ->
%% mnesia:create_table(attributes, [{type, set},
%% {attributes, [name, value, type]},
%% {ram_copies, [node()]},
%% {index, [name]}
%% ]).


Loading
Loading