Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
8f6551b
test(schema): add schema namespace tests for PostgresBackend
vistart Apr 28, 2026
43123ba
feat(schema): add get_default_schema() and schema config to PostgresB…
vistart Apr 28, 2026
f433b88
feat(postgres): add UUID type adapter and gen_random_uuid function fa…
vistart Apr 29, 2026
72666f3
feat(postgres): add pgvector type, adapter, and function factories
vistart Apr 29, 2026
b1627fb
feat(postgres): add PostGIS type, adapter, and function factories
vistart Apr 29, 2026
075eabc
refactor(postgres): rewrite hstore module with Expression/Dialect arc…
vistart Apr 29, 2026
0bccf77
refactor(postgres): add extension-aware function version system
vistart Apr 29, 2026
35ce19f
refactor(tests): move transaction tests into transaction/ subdirectory
vistart Apr 29, 2026
8a27d7f
refactor(postgres): align Expression-Dialect architecture across all …
vistart Apr 29, 2026
bb001f8
test(backend): add protocol implementation completeness tests for Pos…
vistart Apr 29, 2026
2207e57
fix: resolve all ruff lint errors across postgres backend
vistart Apr 29, 2026
7642f46
fix: restore quoted type annotations and update test references
vistart Apr 29, 2026
58dfe3f
fix(tests): update function support tests for FunctionSupportInfo ret…
vistart Apr 29, 2026
f10bdca
feat(postgres): override format_column() with alias-aware schema hand…
vistart Apr 29, 2026
caf5b4d
feat(postgres): add async integration tests and expression-based fixt…
vistart Apr 30, 2026
25e789c
fix(tests): skip pg_stat_statements and pg_walinspect tests on CI env…
vistart Apr 30, 2026
2ce7220
chore: add changelog fragment for PR #33
vistart Apr 30, 2026
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
Expand Up @@ -182,3 +182,4 @@ htmlcov/
# Claude Code temporary files (local only)
.claude/tmp/
.claude/plans/
.claude/plan/
1 change: 1 addition & 0 deletions changelog.d/33.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Added schema namespace support for PostgreSQL backend, including get_default_schema() method, schema-aware column formatting with alias handling, and support for multiple PostgreSQL extensions (PostGIS, pgvector, UUID, hstore).
6 changes: 6 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ rhosocial = ["**/*.pyi", "**/*.py"]
minversion = "7.0"
addopts = "-ra -q"
asyncio_mode = "auto"
asyncio_default_fixture_loop_scope = "function"
testpaths = [
"tests",
]
Expand Down Expand Up @@ -115,9 +116,14 @@ line-length = 100
[tool.ruff]
line-length = 120
target-version = "py38"

[tool.ruff.lint]
select = ["E", "F", "B"]
ignore = []

[tool.ruff.lint.per-file-ignores]
"**/examples/**" = ["E402", "E501"]

[tool.mypy]
python_version = "3.8"
warn_return_any = true
Expand Down
168 changes: 168 additions & 0 deletions src/rhosocial/activerecord/backend/impl/postgres/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,13 @@
from .adapters.xml import PostgresXMLAdapter
from .types.network_address import PostgresMacaddr, PostgresMacaddr8
from .adapters.network_address import PostgresMacaddrAdapter, PostgresMacaddr8Adapter
from .adapters.uuid import PostgresUUIDAdapter
from .types.pgvector import PostgresVector
from .adapters.pgvector import PostgresVectorAdapter
from .types.postgis import PostgresGeometry
from .adapters.postgis import PostgresPostGISAdapter
from .types.hstore import PostgresHstore
from .adapters.hstore import PostgresHstoreAdapter
from .types.text_search import (
PostgresTsVector,
PostgresTsQuery,
Expand Down Expand Up @@ -172,6 +179,83 @@
jsonb_path_query_first,
jsonb_path_exists,
jsonb_path_match,
# pgvector functions
vector_l2_distance,
vector_cosine_distance,
vector_inner_product,
vector_cosine_similarity,
vector_literal,
# PostGIS functions - Construction
st_make_point,
st_geom_from_text,
st_geog_from_text,
st_set_srid,
st_transform,
# PostGIS functions - Predicates
st_contains,
st_intersects,
st_within,
st_dwithin,
st_crosses,
st_touches,
st_overlaps,
# PostGIS functions - Measurements
st_distance,
st_area,
st_length,
# PostGIS functions - Output
st_as_geojson,
st_as_text,
# PostGIS functions - Operations
st_buffer,
st_envelope,
st_centroid,
# hstore functions - Constructors
hstore_from_record,
hstore_from_key_value,
# hstore functions - Key/Value Extraction
hstore_akeys,
hstore_skeys,
hstore_avals,
hstore_svals,
hstore_each,
# hstore functions - Conversion
hstore_to_array,
hstore_to_matrix,
hstore_to_json,
hstore_to_jsonb,
hstore_to_json_loose,
hstore_to_jsonb_loose,
# hstore functions - Subset
hstore_slice,
# hstore functions - Existence
hstore_exist,
hstore_defined,
# hstore functions - Delete
hstore_delete,
hstore_delete_keys,
hstore_delete_pairs,
# hstore functions - Record
hstore_populate_record,
# hstore functions - Operators
hstore_get_value,
hstore_get_value_as_text,
hstore_get_values,
hstore_concat,
hstore_key_exists,
hstore_all_keys_exist,
hstore_any_key_exists,
hstore_contains,
hstore_contained_by,
hstore_subtract_key,
hstore_subtract_keys,
hstore_subtract_pairs,
hstore_to_array_operator,
hstore_to_matrix_operator,
hstore_record_update,
# hstore functions - Subscript
hstore_subscript_get,
hstore_subscript_set,
)


Expand Down Expand Up @@ -336,4 +420,88 @@
"jsonb_path_query_first",
"jsonb_path_exists",
"jsonb_path_match",
# UUID Type
"PostgresUUIDAdapter",
"gen_random_uuid",
"uuid_default_generator",
# pgvector Types
"PostgresVector",
"PostgresVectorAdapter",
"vector_l2_distance",
"vector_cosine_distance",
"vector_inner_product",
"vector_cosine_similarity",
"vector_literal",
# PostGIS Types
"PostgresGeometry",
"PostgresPostGISAdapter",
# hstore Types
"PostgresHstore",
"PostgresHstoreAdapter",
"st_make_point",
"st_geom_from_text",
"st_geog_from_text",
"st_set_srid",
"st_transform",
"st_contains",
"st_intersects",
"st_within",
"st_dwithin",
"st_crosses",
"st_touches",
"st_overlaps",
"st_distance",
"st_area",
"st_length",
"st_as_geojson",
"st_as_text",
"st_buffer",
"st_envelope",
"st_centroid",
# hstore functions - Constructors
"hstore_from_record",
"hstore_from_key_value",
# hstore functions - Key/Value Extraction
"hstore_akeys",
"hstore_skeys",
"hstore_avals",
"hstore_svals",
"hstore_each",
# hstore functions - Conversion
"hstore_to_array",
"hstore_to_matrix",
"hstore_to_json",
"hstore_to_jsonb",
"hstore_to_json_loose",
"hstore_to_jsonb_loose",
# hstore functions - Subset
"hstore_slice",
# hstore functions - Existence
"hstore_exist",
"hstore_defined",
# hstore functions - Delete
"hstore_delete",
"hstore_delete_keys",
"hstore_delete_pairs",
# hstore functions - Record
"hstore_populate_record",
# hstore functions - Operators
"hstore_get_value",
"hstore_get_value_as_text",
"hstore_get_values",
"hstore_concat",
"hstore_key_exists",
"hstore_all_keys_exist",
"hstore_any_key_exists",
"hstore_contains",
"hstore_contained_by",
"hstore_subtract_key",
"hstore_subtract_keys",
"hstore_subtract_pairs",
"hstore_to_array_operator",
"hstore_to_matrix_operator",
"hstore_record_update",
# hstore functions - Subscript
"hstore_subscript_get",
"hstore_subscript_set",
]
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
- enum: Enum types - https://www.postgresql.org/docs/current/datatype-enum.html
- xml: XML type - https://www.postgresql.org/docs/current/datatype-xml.html
- pg_lsn: pg_lsn type - https://www.postgresql.org/docs/current/datatype-pg-lsn.html
- uuid: UUID type - https://www.postgresql.org/docs/current/datatype-uuid.html
- pgvector: pgvector vector type - https://github.com/pgvector/pgvector
"""

# Base types
Expand Down Expand Up @@ -73,6 +75,18 @@
# XML type
from .xml import PostgresXMLAdapter

# UUID type
from .uuid import PostgresUUIDAdapter

# pgvector types
from .pgvector import PostgresVectorAdapter

# PostGIS types
from .postgis import PostgresPostGISAdapter

# hstore types
from .hstore import PostgresHstoreAdapter

__all__ = [
# Basic types
"PostgresListAdapter",
Expand Down Expand Up @@ -104,4 +118,12 @@
"PostgresLsnAdapter",
# XML type
"PostgresXMLAdapter",
# UUID type
"PostgresUUIDAdapter",
# pgvector types
"PostgresVectorAdapter",
# PostGIS types
"PostgresPostGISAdapter",
# hstore types
"PostgresHstoreAdapter",
]
124 changes: 124 additions & 0 deletions src/rhosocial/activerecord/backend/impl/postgres/adapters/hstore.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
# src/rhosocial/activerecord/backend/impl/postgres/adapters/hstore.py
"""
PostgreSQL hstore type adapter.

This module provides the PostgresHstoreAdapter for bidirectional
conversion between Python PostgresHstore objects and PostgreSQL
hstore string representations.

PostgreSQL Documentation: https://www.postgresql.org/docs/current/hstore.html
"""

from typing import Dict, Optional, Type, Union, List

from rhosocial.activerecord.backend.type_adapter import SQLTypeAdapter
from rhosocial.activerecord.backend.impl.postgres.types.hstore import PostgresHstore


class PostgresHstoreAdapter(SQLTypeAdapter):
"""Adapter for converting between PostgresHstore and database values.

Supports conversion from:
- PostgresHstore objects → hstore literal string
- Dict[str, Optional[str]] → hstore literal string (convenience)
- str → passthrough (already formatted)
- None → None

And conversion to:
- hstore string → PostgresHstore object
- PostgresHstore → passthrough
- None → None
"""

@property
def supported_types(self) -> Dict[Type, Type]:
"""Return mapping of Python types to their database representation types."""
return {
PostgresHstore: str,
dict: str,
}

def to_database(
self,
value: Union[PostgresHstore, Dict[str, Optional[str]], str, None],
target_type: Type,
) -> Optional[str]:
"""Convert a Python value to a database-compatible format.

Args:
value: The Python value to convert
target_type: The target database type

Returns:
hstore literal string or None

Raises:
TypeError: If value type is not supported
"""
if value is None:
return None

if isinstance(value, PostgresHstore):
return value.to_postgres_string()

if isinstance(value, dict):
hstore = PostgresHstore(data=value)
return hstore.to_postgres_string()

if isinstance(value, str):
return value

raise TypeError(
f"Cannot convert {type(value).__name__} to hstore. "
f"Expected PostgresHstore, dict, str, or None."
)

def from_database(
self,
value: Union[str, PostgresHstore, Dict, None],
source_type: Type,
) -> Optional[PostgresHstore]:
"""Convert a database value to a Python PostgresHstore object.

Args:
value: The database value to convert
source_type: The source database type

Returns:
PostgresHstore instance or None

Raises:
TypeError: If value type is not supported
"""
if value is None:
return None

if isinstance(value, PostgresHstore):
return value

if isinstance(value, str):
return PostgresHstore.from_postgres_string(value)

if isinstance(value, dict):
return PostgresHstore(data=value)

raise TypeError(
f"Cannot convert {type(value).__name__} from database to PostgresHstore. "
f"Expected str, dict, PostgresHstore, or None."
)

def to_database_batch(
self,
values: List[Union[PostgresHstore, Dict[str, Optional[str]], str, None]],
target_type: Type,
) -> List[Optional[str]]:
"""Convert a batch of Python values to database format."""
return [self.to_database(v, target_type) for v in values]

def from_database_batch(
self,
values: List[Union[str, PostgresHstore, Dict, None]],
source_type: Type,
) -> List[Optional[PostgresHstore]]:
"""Convert a batch of database values to Python PostgresHstore objects."""
return [self.from_database(v, source_type) for v in values]
Loading
Loading