Metadata-Version: 2.1
Name: pgalchemy
Version: 0.1.2
Summary: 
Author: Matthew Beatty
Author-email: beattyml1@gmail.com
Requires-Python: >=3.11,<4.0
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Requires-Dist: alembic (>=1.13.2,<2.0.0)
Requires-Dist: alembic-utils (>=0.8.4,<0.9.0)
Requires-Dist: sqlalchemy (>=2.0.32,<3.0.0)
Description-Content-Type: text/markdown

# pg-rls-sqlalchemy

Work in progress. 

SQLAlchemy and Alembic support for Postgres features like:
- Row Level Security (RLS)
- Policies

Built on top of alembic_utils but provides a more usable interface and a few missing features

## Installation

```shell
pip install pg-rls-sqlalchemy
```

OR 

```shell
poetry add pg-rls-sqlalchemy
```

## Usage

### Using RLS BaseModel
Recommended most projects. This is for projects with majority of tables using RLS which will also be almost all new projects using this library.

```python

from sqlalchemy.orm import declarative_base
from pg_rls import rls_base, policy, Policy, PolicyType, PolicyCommands

BaseModel = rls_base(declarative_base())


@policy(Policy("pol_my_models_select_primary", as_=PolicyType.PERMISSIVE, for_=PolicyCommands.SELECT, using="user_id == auth.uid()"))
@policy(Policy("pol_my_models_delete_primary", as_=PolicyType.PERMISSIVE, for_=PolicyCommands.DELETE, using="user_id == auth.uid()"))
@policy(Policy("pol_my_models_update_primary", as_=PolicyType.PERMISSIVE, for_=PolicyCommands.UPDATE, using="user_id == auth.uid()", with_check="user_id == auth.uid()"))
@policy(Policy("pol_my_models_update_primary", as_=PolicyType.PERMISSIVE, for_=PolicyCommands.INSERT, with_check="user_id == auth.uid()"))
# Equivalent to:
# @policy(Policy("pol_my_models_primary", as_=PolicyType.PERMISSIVE, for_=PolicyCommands.ALL, using="user_id == auth.uid()", with_check="user_id == auth.uid()"))
class MyModel(BaseModel):
    ...
```

### Using RLS Decorator
Only intended for projects with majority of tables without RLS enabled. Usually only for existing projects with most tables not protected using RLS that are only using RLS for a niche use case

This is not recommended for other use cases as it makes it easy for a developer to forget to enable RLS and expose a security vulnerability.
```python

from sqlalchemy.orm import declarative_base
from pg_rls import rls, policy, Policy, PolicyType, PolicyCommands

BaseModel = declarative_base()

@rls()
@policy(Policy("pol_my_models_select_primary", as_=PolicyType.PERMISSIVE, for_=PolicyCommands.SELECT, using="user_id == auth.uid()"))
@policy(Policy("pol_my_models_delete_primary", as_=PolicyType.PERMISSIVE, for_=PolicyCommands.DELETE, using="user_id == auth.uid()"))
@policy(Policy("pol_my_models_update_primary", as_=PolicyType.PERMISSIVE, for_=PolicyCommands.UPDATE, using="user_id == auth.uid()", with_check="user_id == auth.uid()"))
@policy(Policy("pol_my_models_update_primary", as_=PolicyType.PERMISSIVE, for_=PolicyCommands.INSERT, with_check="user_id == auth.uid()"))
# Equivalent to:
# @policy(Policy("pol_my_models_primary", as_=PolicyType.PERMISSIVE, for_=PolicyCommands.ALL, using="user_id == auth.uid()", with_check="user_id == auth.uid()"))
class MyModel(BaseModel):
    ...
```


