Opinionated persistence with PostgreSQL.
This project includes example models and persistence stores. Assuming the testing database exists (see below), the following demonstrates basic usage:
from microcosm.api import create_object_graph
from microcosm_postgres.context import SessionContext, transaction
from microcosm_postgres.example import Company
# create the object graph
graph = create_object_graph(name="example", testing=True)
# wire up the persistence layer to the (testing) database
[company_store] = graph.use("company_store")
# set up a session
with SessionContext(graph) as context:
# drop and create database tables; *only* do this for testing
context.recreate_all()
with transaction():
# create a model
company = company_store.create(Company(name="Acme"))
# prints 1
print company_store.count()
Basics:
- Databases are segmented by microservice; no service can see another's database
- Every microservice connects to its database with a username and a password
- Unit testing uses an real (non-mock) database with a non-overlapping name
- Database names and usernames are generated according to convention
Models:
- Persistent models use a
SQLAlchemy
declarative base class - Persistent operations pass through a unifying
Store
layer - Persistent operations favor explicit queries and deletes over automatic relations and cascades
To change the database host:
config.postgres.host = "myhost"
To change the database password:
config.postgres.password = "mysecretpassword"
Tests (and automated builds) act as the "example" microservice and need a corresponding database and user:
createuser example
createdb -O example example_test_db
createdb -O example example_test_secondary_db
Note that production usage should always create the user with a password. For example:
echo "CREATE ROLE example WITH LOGIN ENCRYPTED PASSWORD 'secret';" | psql
Automated test do not enforce that a password is set because many development environments
(OSX, Circle CI) configure pg_hba.conf
for trusted login from localhost.
If you are updating from microcosm-postgres 1.x to 2.x and use encryption, there are a couple of configuration updates you will need to add in order to keep encryption working as expected.
- the
multi_tenant_key_registry
has two new parameters to account foraws-encryption-sdk
updates account_ids
should be set to the list of AWS account IDs that contain the keys being using for encryptionpartitions
should be the list of AWS partitions used to access your encryption keys. This should be a single item per registry entry
General configuration will look like the existing configuration used for the registry (e.g. using ;
as a delimiter
between items per registry entry).
Full configuration may thus look something like this:
multi_tenant_key_registry=dict(
context_keys="client-id1,client-id2",
key_ids="key1a;key1b,key2a;key2b",
partitions="aws,aws-cn",
account_ids="account-id1a;account-id1b,account-id2",
)
For more information, see the "Discovery Mode" section in: https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/migrate-mkps-v2.html
Version 3.x uses sqlalchemy 2.x, any breaking changes are introduced by sqlalchemy 2.
The official sqlalchemy 2 migration guide contains step to ensure your application is compatible with sqlalchemy 2.
Additionally, follow https://docs.sqlalchemy.org/en/20/changelog/whatsnew_20.html#orm-declarative-models to update your models to use the new declarative styles.
Version 3.1.x also introduced auto retry on disconnect, which is enabled by default. If you want to disable it, set config.postgres.engine_retries
to 0
.
Version 3.2.x introduces horizontal-sharding support