Source code for codegen_database.ext.rls.base
from __future__ import annotations
from dataclasses import dataclass, field
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from sqlalchemy import MetaData
[docs]
@dataclass(frozen=True, eq=True)
class RLSPolicy:
table: str
schema: str
name: str
using: str
with_check: str | None = None
roles: list[str] = field(default_factory=list, hash=False)
permissive: bool = True
cmd: str = "ALL"
@property
def table_fullname(self) -> str:
return f"{self.schema}.{self.table}"
def to_sql_create(self) -> str:
parts = [
f"CREATE POLICY {self.name}",
f"ON {self.table_fullname}",
"AS PERMISSIVE" if self.permissive else "AS RESTRICTIVE",
f"FOR {self.cmd}",
]
if self.roles:
roles_str = ", ".join(self.roles)
parts.append(f"TO {roles_str}")
parts.append(f"USING ({self.using})")
if self.with_check is not None:
parts.append(f"WITH CHECK ({self.with_check})")
return "\n".join(parts)
def to_sql_drop(self) -> str:
return f"DROP POLICY IF EXISTS {self.name} ON {self.table_fullname}"
def to_sql_enable_rls(self) -> str:
return f"ALTER TABLE {self.table_fullname} ENABLE ROW LEVEL SECURITY"
[docs]
@dataclass
class RLSPolicies:
policies: set[RLSPolicy] = field(default_factory=set)
@classmethod
def extract(
cls,
metadata: MetaData,
) -> RLSPolicies:
rls_policies = metadata.info.get("rls_policies", RLSPolicies())
metadata.info["rls_policies"] = rls_policies
return rls_policies
def register_rls_policy(
metadata: MetaData,
policy: RLSPolicy,
) -> None:
RLSPolicies.extract(metadata).policies.add(policy)