Files
secondo-py/tests/test_relation.py
2026-01-24 11:30:02 +08:00

312 lines
8.6 KiB
Python

"""
Tests for Phase 3: Relation Algebra
"""
from pysecondo.core.nested_list import atom, list_nl
from pysecondo.core.types import BaseType, TupleType, RelationType, Attribute
from pysecondo.query_processor import QueryProcessor
from pysecondo.storage.memory import MemoryStorage
from pysecondo.algebras.relation import RelationAlgebra
from pysecondo.algebras.standard import StandardAlgebra
from pysecondo.algebras.base import AlgebraManager
import sys
sys.path.insert(0, '.')
def test_create_relation():
"""Test creating relations"""
print("Testing Create Relation...")
storage = MemoryStorage()
algebra_manager = AlgebraManager()
algebra_manager.register_algebra("StandardAlgebra", StandardAlgebra())
algebra_manager.register_algebra(
"RelationAlgebra",
RelationAlgebra(storage)
)
qp = QueryProcessor(algebra_manager, storage)
# Create a relation
qp.execute_create(
"cities",
"(rel (tuple ((Name string)(Population int))))"
)
# Check it exists
assert storage.object_exists("cities")
obj_type = storage.get_type("cities")
assert isinstance(obj_type, RelationType)
print(" ✓ Create relation tests passed")
def test_update_relation():
"""Test updating relations with data"""
print("Testing Update Relation...")
storage = MemoryStorage()
algebra_manager = AlgebraManager()
algebra_manager.register_algebra("StandardAlgebra", StandardAlgebra())
algebra_manager.register_algebra(
"RelationAlgebra",
RelationAlgebra(storage)
)
qp = QueryProcessor(algebra_manager, storage)
# Create and populate a relation
qp.execute_create(
"cities",
"(rel (tuple ((Name string)(Population int))))"
)
# Insert data
cities_data = list_nl(
list_nl("Beijing", 21540000),
list_nl("Shanghai", 24280000),
list_nl("Guangzhou", 14040000),
)
qp.execute_update("cities", cities_data)
# Verify data
cities = qp.lookup_identifier("cities")
assert len(cities) == 3
print(" ✓ Update relation tests passed")
def test_feed_consume():
"""Test feed and consume operators"""
print("Testing Feed and Consume...")
storage = MemoryStorage()
algebra_manager = AlgebraManager()
algebra_manager.register_algebra("StandardAlgebra", StandardAlgebra())
algebra_manager.register_algebra(
"RelationAlgebra",
RelationAlgebra(storage)
)
qp = QueryProcessor(algebra_manager, storage)
# Create and populate a relation
qp.execute_create(
"cities",
"(rel (tuple ((Name string)(Population int))))"
)
cities_data = list_nl(
list_nl("Beijing", 21540000),
list_nl("Shanghai", 24280000),
list_nl("Guangzhou", 14040000),
)
qp.execute_update("cities", cities_data)
# Test feed: relation -> stream
cities = qp.lookup_identifier("cities")
cities_type = qp.get_identifier_type("cities")
feed_op = algebra_manager.get_operator("feed")
stream = feed_op.value_map([cities])
assert len(stream) == 3
# Test consume: stream -> relation
consume_op = algebra_manager.get_operator("consume")
result = consume_op.value_map([stream])
assert len(result) == 3
print(" ✓ Feed and consume tests passed")
def test_count():
"""Test count operator"""
print("Testing Count Operator...")
storage = MemoryStorage()
algebra_manager = AlgebraManager()
algebra_manager.register_algebra("StandardAlgebra", StandardAlgebra())
algebra_manager.register_algebra(
"RelationAlgebra",
RelationAlgebra(storage)
)
qp = QueryProcessor(algebra_manager, storage)
# Create and populate a relation
qp.execute_create(
"cities",
"(rel (tuple ((Name string)(Population int))))"
)
cities_data = list_nl(
list_nl("Beijing", 21540000),
list_nl("Shanghai", 24280000),
list_nl("Guangzhou", 14040000),
list_nl("Shenzhen", 17560000),
)
qp.execute_update("cities", cities_data)
# Test count
cities = qp.lookup_identifier("cities")
feed_op = algebra_manager.get_operator("feed")
count_op = algebra_manager.get_operator("count")
stream = feed_op.value_map([cities])
count_result = count_op.value_map([stream])
assert count_result.value == 4
print(" ✓ Count operator tests passed")
def test_filter():
"""Test filter operator"""
print("Testing Filter Operator...")
storage = MemoryStorage()
algebra_manager = AlgebraManager()
algebra_manager.register_algebra("StandardAlgebra", StandardAlgebra())
algebra_manager.register_algebra(
"RelationAlgebra",
RelationAlgebra(storage)
)
qp = QueryProcessor(algebra_manager, storage)
# Create and populate a relation
qp.execute_create(
"cities",
"(rel (tuple ((Name string)(Population int))))"
)
cities_data = list_nl(
list_nl("Beijing", 21540000),
list_nl("Shanghai", 24280000),
list_nl("Guangzhou", 14040000),
list_nl("Shenzhen", 17560000),
)
qp.execute_update("cities", cities_data)
# Test filter with true (pass all)
cities = qp.lookup_identifier("cities")
feed_op = algebra_manager.get_operator("feed")
filter_op = algebra_manager.get_operator("filter")
stream = feed_op.value_map([cities])
filtered = filter_op.value_map([stream, atom(True)])
assert len(filtered) == 4
# Test filter with false (pass none)
filtered = filter_op.value_map([stream, atom(False)])
assert len(filtered) == 0
print(" ✓ Filter operator tests passed")
def test_query_pipeline():
"""Test a complete query pipeline"""
print("Testing Query Pipeline...")
storage = MemoryStorage()
algebra_manager = AlgebraManager()
algebra_manager.register_algebra("StandardAlgebra", StandardAlgebra())
algebra_manager.register_algebra(
"RelationAlgebra",
RelationAlgebra(storage)
)
qp = QueryProcessor(algebra_manager, storage)
# Setup: create cities relation
qp.execute_create(
"cities",
"(rel (tuple ((Name string)(Population int))))"
)
cities_data = list_nl(
list_nl("Beijing", 21540000),
list_nl("Shanghai", 24280000),
list_nl("Guangzhou", 14040000),
list_nl("Shenzhen", 17560000),
list_nl("Hangzhou", 12200000),
)
qp.execute_update("cities", cities_data)
# Query: cities feed count
# Equivalent to: SELECT COUNT(*) FROM cities
cities = qp.lookup_identifier("cities")
feed_op = algebra_manager.get_operator("feed")
count_op = algebra_manager.get_operator("count")
stream = feed_op.value_map([cities])
count = count_op.value_map([stream])
assert count.value == 5
# Query: cities feed filter[true] consume
# Equivalent to: SELECT * FROM cities
filter_op = algebra_manager.get_operator("filter")
consume_op = algebra_manager.get_operator("consume")
stream = feed_op.value_map([cities])
filtered = filter_op.value_map([stream, atom(True)])
result = consume_op.value_map([filtered])
assert len(result) == 5
print(" ✓ Query pipeline tests passed")
def test_type_checking():
"""Test type checking for relation operators"""
print("Testing Type Checking for Relations...")
algebra_manager = AlgebraManager()
algebra_manager.register_algebra("StandardAlgebra", StandardAlgebra())
storage = MemoryStorage()
algebra_manager.register_algebra(
"RelationAlgebra",
RelationAlgebra(storage)
)
# Test feed type mapping
feed_op = algebra_manager.get_operator("feed")
tuple_type = TupleType([
Attribute("Name", BaseType.STRING),
Attribute("Population", BaseType.INT)
])
rel_type = RelationType(tuple_type)
result_type = feed_op.type_map([rel_type])
assert result_type == tuple_type
# Test consume type mapping
consume_op = algebra_manager.get_operator("consume")
result_type = consume_op.type_map([tuple_type])
assert isinstance(result_type, RelationType)
assert result_type.tuple_type == tuple_type
# Test count type mapping
count_op = algebra_manager.get_operator("count")
result_type = count_op.type_map([tuple_type])
assert result_type == BaseType.INT
print(" ✓ Type checking tests passed")
if __name__ == "__main__":
print("=" * 50)
print("Phase 3: Relation Algebra Tests")
print("=" * 50)
test_create_relation()
test_update_relation()
test_feed_consume()
test_count()
test_filter()
test_query_pipeline()
test_type_checking()
print("\n" + "=" * 50)
print("All Phase 3 tests passed! ✓")
print("=" * 50)