mirror of
https://github.com/djrobstep/migra.git
synced 2024-09-11 13:56:05 +03:00
trigger support, add using casts, readme enhance
This commit is contained in:
parent
78c779620c
commit
6d507eae09
30
README.md
30
README.md
@ -18,6 +18,16 @@ You can also detect changes for a single specific schema only with `--schema mys
|
||||
|
||||
**Migra supports PostgreSQL >= 10 only.** Known issues exist with earlier versions. Development resources are limited, and feature support rather than backwards compatibility is prioritised.
|
||||
|
||||
## Support `migra`'s maintenance and future development
|
||||
|
||||
This project isn't sponsored by my employer or any other organisation: It's been built with many hours of voluntary unpaid work.
|
||||
|
||||
I've recently set up [a Patreon](https://patreon.com/djrobstep) to help support future development of `migra` and related projects.
|
||||
|
||||
If you or your employer uses `migra`, please consider [becoming a subscriber](https://patreon.com/djrobstep).
|
||||
|
||||
If you require specific features or support, more formal commercial arrangements can be discussed (email me at the author email specified in this repo's `pyproject.toml`)
|
||||
|
||||
## Folks, schemas are good
|
||||
|
||||
Schema migrations are without doubt the most cumbersome and annoying part of working with SQL databases. So much so that some people think that schemas themselves are bad!
|
||||
@ -66,9 +76,25 @@ If you want to generate `drop ...` statements, you need to use the `--unsafe` fl
|
||||
|
||||
## Features and Limitations
|
||||
|
||||
`migra` plays nicely with extensions. Schema contents belonging to extensions will be ignored and left to the extension to manage.
|
||||
Table of supported features:
|
||||
|
||||
`migra` supports most PostgreSQL features: tables (including partitioning), views, functions, constraints, indexes, enums, collations, extensions, row level security policies, schemas and sequences.
|
||||
Feature | Supported | Notes/limitations
|
||||
--- | --- | ---
|
||||
tables | ✔ |
|
||||
partitioned tables | ✔ | NEW!
|
||||
constraints | ✔ |
|
||||
views | ✔ |
|
||||
functions | ✔ | Dependency-aware. All languages except C/INTERNAL
|
||||
sequences | ✔ | Does not track sequence numbers
|
||||
schemas | ✔ |
|
||||
extensions | ✔ |
|
||||
enums | ✔ |
|
||||
privileges | ✔ | Not exhaustive. Requires --with-privileges flag
|
||||
row-level security | ✔ | NEW! Doesn't include role management
|
||||
triggers | ✔ | NEW!
|
||||
custom types/domains | In progress |
|
||||
|
||||
`migra` plays nicely with extensions. Schema contents belonging to extensions will be ignored and left to the extension to manage.
|
||||
|
||||
`migra` plays nicely with view/function dependencies, and will drop/create them in the correct order.
|
||||
|
||||
|
@ -18,6 +18,7 @@ THINGS = [
|
||||
"privileges",
|
||||
"collations",
|
||||
"rlspolicies",
|
||||
"triggers"
|
||||
]
|
||||
PK = "PRIMARY KEY"
|
||||
|
||||
|
@ -64,10 +64,12 @@ class Migration(object):
|
||||
|
||||
def add_all_changes(self, privileges=False):
|
||||
self.add(self.changes.schemas(creations_only=True))
|
||||
|
||||
self.add(self.changes.extensions(creations_only=True))
|
||||
self.add(self.changes.collations(creations_only=True))
|
||||
self.add(self.changes.enums(creations_only=True, modifications=False))
|
||||
self.add(self.changes.sequences(creations_only=True))
|
||||
self.add(self.changes.triggers(drops_only=True))
|
||||
self.add(self.changes.rlspolicies(drops_only=True))
|
||||
if privileges:
|
||||
self.add(self.changes.privileges(drops_only=True))
|
||||
@ -75,6 +77,7 @@ class Migration(object):
|
||||
self.add(self.changes.pk_constraints(drops_only=True))
|
||||
self.add(self.changes.indexes(drops_only=True))
|
||||
|
||||
|
||||
self.add(self.changes.selectables())
|
||||
|
||||
self.add(self.changes.sequences(drops_only=True))
|
||||
@ -86,6 +89,7 @@ class Migration(object):
|
||||
if privileges:
|
||||
self.add(self.changes.privileges(creations_only=True))
|
||||
self.add(self.changes.rlspolicies(creations_only=True))
|
||||
self.add(self.changes.triggers(creations_only=True))
|
||||
self.add(self.changes.collations(drops_only=True))
|
||||
self.add(self.changes.schemas(drops_only=True))
|
||||
|
||||
|
@ -13,7 +13,7 @@ homepage = "https://migra.djrobstep.com/"
|
||||
python = "*"
|
||||
sqlbag = "*"
|
||||
six = "*"
|
||||
schemainspect = ">=0.1.1543655873"
|
||||
schemainspect = ">= 0.1.1543708870"
|
||||
psycopg2-binary = { version="*", optional = true }
|
||||
|
||||
[tool.poetry.dev-dependencies]
|
||||
|
@ -1,5 +1,5 @@
|
||||
alter table "public"."t" add column "c" text collate "numeric";
|
||||
|
||||
alter table "public"."t" alter column "b" set data type text collate "numeric";
|
||||
alter table "public"."t" alter column "b" set data type text collate "numeric" using "b"::text;
|
||||
|
||||
drop collation if exists "public"."posix";
|
||||
|
@ -64,7 +64,7 @@ create table "public"."order_items" (
|
||||
);
|
||||
|
||||
|
||||
alter table "public"."orders" alter column "status" set data type varchar;
|
||||
alter table "public"."orders" alter column "status" set data type varchar using "status"::varchar;
|
||||
|
||||
drop type "public"."shipping_status";
|
||||
|
||||
@ -80,7 +80,7 @@ alter table "public"."orders" add column "h" hstore;
|
||||
|
||||
alter table "public"."orders" alter column "order_id" drop default;
|
||||
|
||||
alter table "public"."orders" alter column "status2" set data type text;
|
||||
alter table "public"."orders" alter column "status2" set data type text using "status2"::text;
|
||||
|
||||
alter table "public"."products" drop column "oldcolumn";
|
||||
|
||||
@ -94,7 +94,7 @@ alter table "public"."products" add column "newcolumn2" interval;
|
||||
|
||||
alter table "public"."products" alter column "name" drop not null;
|
||||
|
||||
alter table "public"."products" alter column "name" set data type text;
|
||||
alter table "public"."products" alter column "name" set data type text using "name"::text;
|
||||
|
||||
alter table "public"."products" alter column "price" set default 100;
|
||||
|
||||
|
@ -64,7 +64,7 @@ create table "public"."order_items" (
|
||||
);
|
||||
|
||||
|
||||
alter table "public"."orders" alter column "status" set data type varchar;
|
||||
alter table "public"."orders" alter column "status" set data type varchar using "status"::varchar;
|
||||
|
||||
drop type "public"."shipping_status";
|
||||
|
||||
@ -80,7 +80,7 @@ alter table "public"."orders" add column "h" hstore;
|
||||
|
||||
alter table "public"."orders" alter column "order_id" drop default;
|
||||
|
||||
alter table "public"."orders" alter column "status2" set data type text;
|
||||
alter table "public"."orders" alter column "status2" set data type text using "status2"::text;
|
||||
|
||||
alter table "public"."products" drop column "z";
|
||||
|
||||
@ -90,7 +90,7 @@ alter table "public"."products" add column "newcolumn2" interval;
|
||||
|
||||
alter table "public"."products" alter column "name" drop not null;
|
||||
|
||||
alter table "public"."products" alter column "name" set data type text;
|
||||
alter table "public"."products" alter column "name" set data type text using "name"::text;
|
||||
|
||||
alter table "public"."products" alter column "price" set default 100;
|
||||
|
||||
|
34
tests/FIXTURES/triggers/a.sql
Normal file
34
tests/FIXTURES/triggers/a.sql
Normal file
@ -0,0 +1,34 @@
|
||||
CREATE TABLE emp (
|
||||
empname text,
|
||||
salary integer,
|
||||
last_date timestamp,
|
||||
last_user text
|
||||
);
|
||||
|
||||
CREATE FUNCTION emp_stamp() RETURNS trigger AS $emp_stamp$
|
||||
BEGIN
|
||||
-- Check that empname and salary are given
|
||||
IF NEW.empname IS NULL THEN
|
||||
RAISE EXCEPTION 'empname cannot be null';
|
||||
END IF;
|
||||
IF NEW.salary IS NULL THEN
|
||||
RAISE EXCEPTION '% cannot have null salary', NEW.empname;
|
||||
END IF;
|
||||
|
||||
-- Who works for us when they must pay for it?
|
||||
IF NEW.salary < 0 THEN
|
||||
RAISE EXCEPTION '% cannot have a negative salary', NEW.empname;
|
||||
END IF;
|
||||
|
||||
-- Remember who changed the payroll when
|
||||
NEW.last_date := current_timestamp;
|
||||
NEW.last_user := current_user;
|
||||
RETURN NEW;
|
||||
END;
|
||||
$emp_stamp$ LANGUAGE plpgsql;
|
||||
|
||||
CREATE TRIGGER emp_stamp BEFORE INSERT OR UPDATE ON emp
|
||||
FOR EACH ROW EXECUTE PROCEDURE emp_stamp();
|
||||
|
||||
CREATE TRIGGER emp_stamp_drop BEFORE INSERT OR UPDATE ON emp
|
||||
FOR EACH ROW EXECUTE PROCEDURE emp_stamp();
|
0
tests/FIXTURES/triggers/additions.sql
Normal file
0
tests/FIXTURES/triggers/additions.sql
Normal file
34
tests/FIXTURES/triggers/b.sql
Normal file
34
tests/FIXTURES/triggers/b.sql
Normal file
@ -0,0 +1,34 @@
|
||||
CREATE TABLE emp (
|
||||
empname text,
|
||||
salary integer,
|
||||
last_date timestamp,
|
||||
last_user text
|
||||
);
|
||||
|
||||
CREATE FUNCTION emp_stamp() RETURNS trigger AS $emp_stamp$
|
||||
BEGIN
|
||||
-- Check that empname and salary are given
|
||||
IF NEW.empname IS NULL THEN
|
||||
RAISE EXCEPTION 'empname cannot be null';
|
||||
END IF;
|
||||
IF NEW.salary IS NULL THEN
|
||||
RAISE EXCEPTION '% cannot have null salary', NEW.empname;
|
||||
END IF;
|
||||
|
||||
-- Who works for us when they must pay for it?
|
||||
IF NEW.salary < 0 THEN
|
||||
RAISE EXCEPTION '% cannot have a negative salary', NEW.empname;
|
||||
END IF;
|
||||
|
||||
-- Remember who changed the payroll when
|
||||
NEW.last_date := current_timestamp;
|
||||
NEW.last_user := current_user;
|
||||
RETURN NEW;
|
||||
END;
|
||||
$emp_stamp$ LANGUAGE plpgsql;
|
||||
|
||||
CREATE TRIGGER emp_stamp BEFORE UPDATE ON emp
|
||||
FOR EACH ROW EXECUTE PROCEDURE emp_stamp();
|
||||
|
||||
CREATE TRIGGER emp_stamp_create BEFORE INSERT OR UPDATE ON emp
|
||||
FOR EACH ROW EXECUTE PROCEDURE emp_stamp();
|
7
tests/FIXTURES/triggers/expected.sql
Normal file
7
tests/FIXTURES/triggers/expected.sql
Normal file
@ -0,0 +1,7 @@
|
||||
drop trigger if exists "emp_stamp_drop" on "public"."emp";
|
||||
|
||||
drop trigger if exists "emp_stamp" on "public"."emp";
|
||||
|
||||
CREATE TRIGGER emp_stamp_create BEFORE INSERT OR UPDATE ON public.emp FOR EACH ROW EXECUTE PROCEDURE emp_stamp();
|
||||
|
||||
CREATE TRIGGER emp_stamp BEFORE UPDATE ON public.emp FOR EACH ROW EXECUTE PROCEDURE emp_stamp();
|
0
tests/FIXTURES/triggers/expected2.sql
Normal file
0
tests/FIXTURES/triggers/expected2.sql
Normal file
@ -54,6 +54,11 @@ def test_collations():
|
||||
do_fixture_test(FIXTURE_NAME)
|
||||
|
||||
|
||||
def test_triggers():
|
||||
for FIXTURE_NAME in ["triggers"]:
|
||||
do_fixture_test(FIXTURE_NAME)
|
||||
|
||||
|
||||
def test_singleschemea():
|
||||
for FIXTURE_NAME in ["singleschema"]:
|
||||
do_fixture_test(FIXTURE_NAME, schema="goodschema")
|
||||
|
Loading…
Reference in New Issue
Block a user