-module(infinite_relations_test). -include_lib("eunit/include/eunit.hrl"). -include("operations.hrl"). %%% Test Suite for Infinite Relations infinite_relations_test_() -> {foreach, fun setup/0, fun cleanup/1, [ fun test_create_naturals/1, fun test_naturals_with_constraints/1, fun test_integers_generator/1, fun test_rationals_generator/1, fun test_take_operator/1, fun test_finite_relation_cardinality/1 ]}. %%% Setup and Cleanup setup() -> operations:setup(), operations:create_database(test_db). cleanup(_DB) -> ok. %%% Helper Functions %% Strip metadata from tuples for comparison strip_meta(Tuple) when is_map(Tuple) -> maps:remove(meta, Tuple); strip_meta(Tuples) when is_list(Tuples) -> [strip_meta(T) || T <- Tuples]. %%% Tests test_create_naturals(DB) -> %% Create infinite relation of natural numbers %% Domain relations have empty schemas (base case) {DB1, Naturals} = operations:create_infinite_relation(DB, #{ name => naturals, schema => #{}, cardinality => aleph_zero, generator => {primitive, naturals}, constraints => #{value => {gte, 0}} }), [ ?_assert(is_record(Naturals, relation)), ?_assertEqual(naturals, Naturals#relation.name), ?_assertEqual(aleph_zero, Naturals#relation.cardinality), ?_assertEqual({primitive, naturals}, Naturals#relation.generator) ]. test_naturals_with_constraints(DB) -> %% Create naturals relation {DB1, _Naturals} = operations:create_infinite_relation(DB, #{ name => naturals, schema => #{}, cardinality => aleph_zero, generator => {primitive, naturals}, constraints => #{value => {gte, 0}} }), %% Query with range constraint [0, 9] Iterator = operations:get_tuples_iterator(DB1, naturals, #{value => {range, 0, 9}}), Tuples = operations:collect_all(Iterator), DataOnly = strip_meta(Tuples), %% Should get exactly 10 tuples: {0, 1, 2, ..., 9} [ ?_assertEqual(10, length(Tuples)), ?_assert(lists:member(#{value => 0}, DataOnly)), ?_assert(lists:member(#{value => 5}, DataOnly)), ?_assert(lists:member(#{value => 9}, DataOnly)) ]. test_integers_generator(DB) -> %% Create integers relation {DB1, Integers} = operations:create_infinite_relation(DB, #{ name => integers, schema => #{}, cardinality => aleph_zero, generator => {primitive, integers} }), %% Query with range constraint [-5, 5] Iterator = operations:get_tuples_iterator(DB1, integers, #{value => {range, -5, 5}}), Tuples = operations:collect_all(Iterator), DataOnly = strip_meta(Tuples), %% Should get 11 tuples: {-5, -4, ..., 0, ..., 4, 5} [ ?_assertEqual(aleph_zero, Integers#relation.cardinality), ?_assertEqual(11, length(Tuples)), ?_assert(lists:member(#{value => 0}, DataOnly)), ?_assert(lists:member(#{value => -5}, DataOnly)), ?_assert(lists:member(#{value => 5}, DataOnly)) ]. test_rationals_generator(DB) -> %% Create rationals relation {DB1, Rationals} = operations:create_infinite_relation(DB, #{ name => rationals, schema => #{}, cardinality => aleph_zero, generator => {primitive, rationals} }), %% Take first 10 rationals using constraints Iterator = operations:get_tuples_iterator(DB1, rationals, #{}), %% Just get a few tuples to verify generator works {ok, First} = operations:next_tuple(Iterator), {ok, Second} = operations:next_tuple(Iterator), operations:close_iterator(Iterator), [ ?_assertEqual(aleph_zero, Rationals#relation.cardinality), ?_assert(is_map(First)), ?_assert(maps:is_key(numerator, First)), ?_assert(maps:is_key(denominator, First)), ?_assert(is_map(Second)) ]. test_take_operator(DB) -> %% Create naturals {DB1, _} = operations:create_infinite_relation(DB, #{ name => naturals, schema => #{}, cardinality => aleph_zero, generator => {primitive, naturals}, constraints => #{value => {gte, 0}} }), %% Take 100 naturals {_DB2, Naturals100} = operations:take(DB1, naturals, 100), %% Verify result is finite [ ?_assertEqual({finite, 100}, Naturals100#relation.cardinality), ?_assertEqual({take, naturals, 100}, Naturals100#relation.generator) ]. test_finite_relation_cardinality(DB) -> %% Create finite relation {DB1, _} = operations:create_relation(DB, users, #{name => string, age => integer}), %% Add tuple {DB2, UpdatedRel} = operations:create_tuple(DB1, users, #{name => "Alice", age => 30}), %% Cardinality should be 1 [ ?_assertEqual({finite, 1}, UpdatedRel#relation.cardinality) ].