Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial MySQL support (early draft) - JSONField version #91

Merged
merged 25 commits into from
Jun 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
a4d210e
use custom ArrayField type in migrations
Joshun May 10, 2023
f87004c
start rewriting check_leg_trigger for mysql
Joshun May 10, 2023
14b7233
check_leg trigger called in on_commit
Joshun May 10, 2023
951dff3
update check_leg to newer version
Joshun May 10, 2023
f558bf2
fix broken postgres procedure due to % escaping
Joshun May 10, 2023
abd51bd
check_account_type trigger in mysql
Joshun May 10, 2023
a2633bc
tidyup of historic migrations
Joshun May 10, 2023
db60184
only run on postgres
Joshun May 10, 2023
9cbbbeb
correct version comment
Joshun May 10, 2023
12beda2
adapt for postgres + mysql
Joshun May 10, 2023
15ab2a8
get update_full_account_codes working
Joshun May 11, 2023
3f46031
document _enforce_account
Joshun May 11, 2023
d529c88
fix check_leg_and_account_currency_match in mysql
Joshun May 11, 2023
5d12678
fix escaping broken in postgres migration
Joshun May 12, 2023
7216a90
clean up debugging statements
Joshun May 12, 2023
5817d00
add mysqlclient to requirements.txt
Joshun May 16, 2023
04bfdef
make lint happy
Joshun May 16, 2023
85a7bc4
cleanup for lint
Joshun May 17, 2023
8803100
Testing JSONField replacement requirement
nitsujri May 16, 2023
67fd1a4
migration to JSONField in remaining places, with special logic for Po…
Joshun May 17, 2023
ac5b677
clarify migration logic
Joshun May 17, 2023
68c58f5
remaining changes for MySQL compatibility:
Joshun May 31, 2023
88108e0
remove mysqlclient from requirements.txt and add it to requirements_t…
Joshun Jun 8, 2023
c1ddae5
remove psycopg2-binary from requirements.txt and add it to requiremen…
Joshun Jun 8, 2023
a379523
install requirements_test.txt before running lint
Joshun Jun 8, 2023
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
23 changes: 22 additions & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,14 @@ jobs:
--health-retries 5
ports:
- 5432:5432
mariadb:
image: mariadb
env:
MARIADB_DATABASE: mariadb
MYSQL_ALLOW_EMPTY_PASSWORD: yes
options: --health-cmd="mysqladmin ping" --health-interval=5s --health-timeout=2s --health-retries=3
ports:
- 3306:3306

steps:
- uses: actions/checkout@v2
Expand All @@ -64,6 +72,8 @@ jobs:

- name: Install
run: |
sudo apt-get update
sudo apt-get install -y mariadb-client-10.6
python setup.py develop
pip install -e .
pip install -r requirements_test.txt
Expand All @@ -77,14 +87,24 @@ jobs:
pip install "py-moneyed>=3" --upgrade # Different version of py-moneyed should not create different migrations
PYTHONPATH=`pwd` ./manage.py makemigrations --check hordak

- name: Testing
- name: Testing (PostgreSQL)
run: |
PYTHONPATH=`pwd` python -Wall -W error::DeprecationWarning -m coverage run ./manage.py test hordak
pip install -e .[subqueries]
PYTHONPATH=`pwd` python -Wall -W error::DeprecationWarning -m coverage run --append ./manage.py test hordak # Test with subquery
coverage xml && codecov
env:
DATABASE_URL: "postgresql://postgres:postgres@localhost/postgres"
- name: Testing (MariaDB)
run: |
PYTHONPATH=`pwd` ./manage.py makemigrations --check hordak

PYTHONPATH=`pwd` python -Wall -W error::DeprecationWarning -m coverage run ./manage.py test hordak
pip install -e .[subqueries]
PYTHONPATH=`pwd` python -Wall -W error::DeprecationWarning -m coverage run --append ./manage.py test hordak # Test with subquery
coverage xml && codecov
env:
DATABASE_URL: "mysql://[email protected]:3306/mariadb"

lint:
runs-on: ubuntu-latest
Expand All @@ -101,6 +121,7 @@ jobs:
run: |
pip install flake8 isort black mypy django-stubs dj_database_url types-six types-requests types-mock
pip install "django-stubs<1.13.0" # Remove this line once https://github.com/typeddjango/django-stubs/issues/1227 is fixed
pip install -r requirements_test.txt
python setup.py develop
pip install -e .
- name: Running Flake8
Expand Down
91 changes: 57 additions & 34 deletions hordak/migrations/0002_check_leg_trigger_20160903_1149.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,42 +5,65 @@
from django.db import migrations


def create_trigger(apps, schema_editor):
if schema_editor.connection.vendor == "postgresql":
schema_editor.execute(
"""
CREATE OR REPLACE FUNCTION check_leg()
RETURNS trigger AS
$$
DECLARE
transaction_sum DECIMAL(13, 2);
BEGIN

IF (TG_OP = 'DELETE') THEN
SELECT SUM(amount) INTO transaction_sum FROM hordak_leg WHERE transaction_id = OLD.transaction_id;
ELSE
SELECT SUM(amount) INTO transaction_sum FROM hordak_leg WHERE transaction_id = NEW.transaction_id;
END IF;

IF transaction_sum != 0 THEN
RAISE EXCEPTION 'Sum of transaction amounts must be 0';
END IF;
RETURN NEW;
END;
$$
LANGUAGE plpgsql
"""
)
schema_editor.execute(
"""
CREATE CONSTRAINT TRIGGER check_leg_trigger
AFTER INSERT OR UPDATE OR DELETE ON hordak_leg
DEFERRABLE INITIALLY DEFERRED
FOR EACH ROW EXECUTE PROCEDURE check_leg();
"""
)

elif schema_editor.connection.vendor == "mysql":
pass # we don't care about MySQL here since support is added in 0006
else:
raise NotImplementedError(
"Database vendor %s not supported" % schema_editor.connection.vendor
)


def drop_trigger(apps, schema_editor):
if schema_editor.connection.vendor == "postgresql":
schema_editor.execute("DROP FUNCTION check_leg()")
schema_editor.execute("DROP TRIGGER IF EXISTS check_leg_trigger ON hordak_leg")
elif schema_editor.connection.vendor == "mysql":
pass
else:
raise NotImplementedError(
"Database vendor %s not supported" % schema_editor.connection.vendor
)


class Migration(migrations.Migration):
dependencies = [("hordak", "0001_initial")]
atomic = False

operations = [
migrations.RunSQL(
"""
CREATE OR REPLACE FUNCTION check_leg()
RETURNS trigger AS
$$
DECLARE
transaction_sum DECIMAL(13, 2);
BEGIN

IF (TG_OP = 'DELETE') THEN
SELECT SUM(amount) INTO transaction_sum FROM hordak_leg WHERE transaction_id = OLD.transaction_id;
ELSE
SELECT SUM(amount) INTO transaction_sum FROM hordak_leg WHERE transaction_id = NEW.transaction_id;
END IF;

IF transaction_sum != 0 THEN
RAISE EXCEPTION 'Sum of transaction amounts must be 0';
END IF;
RETURN NEW;
END;
$$
LANGUAGE plpgsql
""",
"DROP FUNCTION check_leg()",
),
migrations.RunSQL(
"""
CREATE CONSTRAINT TRIGGER check_leg_trigger
AFTER INSERT OR UPDATE OR DELETE ON hordak_leg
DEFERRABLE INITIALLY DEFERRED
FOR EACH ROW EXECUTE PROCEDURE check_leg();
""",
"DROP TRIGGER IF EXISTS check_leg_trigger ON hordak_leg",
),
migrations.RunPython(create_trigger, reverse_code=drop_trigger),
]
7 changes: 3 additions & 4 deletions hordak/migrations/0005_account_currencies.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
import django.contrib.postgres.fields
from django.db import migrations, models

import hordak.models.core


class Migration(migrations.Migration):
dependencies = [("hordak", "0004_auto_20161113_1932")]
Expand All @@ -13,11 +15,8 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name="account",
name="currencies",
field=django.contrib.postgres.fields.ArrayField(
base_field=models.CharField(max_length=3),
db_index=True,
field=models.JSONField(
default=["EUR"],
size=None,
),
preserve_default=False,
)
Expand Down
110 changes: 74 additions & 36 deletions hordak/migrations/0006_auto_20161209_0108.py
Original file line number Diff line number Diff line change
@@ -1,47 +1,85 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.1 on 2016-12-09 01:08
# Generated by Django 1.10.1 on 2016-09-03 11:49
from __future__ import unicode_literals

from django.db import migrations


def create_trigger(apps, schema_editor):
if schema_editor.connection.vendor == "postgresql":
schema_editor.execute(
"""
CREATE OR REPLACE FUNCTION check_leg()
RETURNS trigger AS
$$
DECLARE
tx_id INT;
non_zero RECORD;
BEGIN
IF (TG_OP = 'DELETE') THEN
tx_id := OLD.transaction_id;
ELSE
tx_id := NEW.transaction_id;
END IF;


SELECT ABS(SUM(amount)) AS total, amount_currency AS currency
INTO non_zero
FROM hordak_leg
WHERE transaction_id = tx_id
GROUP BY amount_currency
HAVING ABS(SUM(amount)) > 0
LIMIT 1;

IF FOUND THEN
RAISE EXCEPTION 'Sum of transaction amounts in each currency must be 0. Currency %% has non-zero total %%',
non_zero.currency, non_zero.total;
END IF;

RETURN NEW;
END;
$$
LANGUAGE plpgsql;

"""
)

elif schema_editor.connection.vendor == "mysql":
# we have to call this procedure in Leg.on_commit, because MySQL does not support deferred triggers
schema_editor.execute(
"""
CREATE OR REPLACE PROCEDURE check_leg(_transaction_id INT)
BEGIN
DECLARE transaction_sum DECIMAL(13, 2);
DECLARE transaction_currency VARCHAR(3);

SELECT ABS(SUM(amount)) AS total, amount_currency AS currency
INTO transaction_sum, transaction_currency
FROM hordak_leg
WHERE transaction_id = _transaction_id
GROUP BY amount_currency
HAVING ABS(SUM(amount)) > 0
LIMIT 1;

IF FOUND_ROWS() > 0 THEN
SET @msg= CONCAT('Sum of transaction amounts must be 0, got ', transaction_sum);
SIGNAL SQLSTATE '45000' SET
MESSAGE_TEXT = @msg;
END IF;

END
"""
)
else:
raise NotImplementedError(
"Database vendor %s not supported" % schema_editor.connection.vendor
)


class Migration(migrations.Migration):
dependencies = [("hordak", "0005_account_currencies")]
atomic = False

operations = [
migrations.RunSQL(
"""
CREATE OR REPLACE FUNCTION check_leg()
RETURNS trigger AS
$$
DECLARE
tx_id INT;
non_zero RECORD;
BEGIN
IF (TG_OP = 'DELETE') THEN
tx_id := OLD.transaction_id;
ELSE
tx_id := NEW.transaction_id;
END IF;


SELECT ABS(SUM(amount)) AS total, amount_currency AS currency
INTO non_zero
FROM hordak_leg
WHERE transaction_id = tx_id
GROUP BY amount_currency
HAVING ABS(SUM(amount)) > 0
LIMIT 1;

IF FOUND THEN
RAISE EXCEPTION 'Sum of transaction amounts in each currency must be 0. Currency % has non-zero total %',
non_zero.currency, non_zero.total;
END IF;

RETURN NEW;
END;
$$
LANGUAGE plpgsql;
"""
)
migrations.RunPython(create_trigger),
]
Loading