flask-postgresql-audit 1.1.2__tar.gz → 1.1.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {flask_postgresql_audit-1.1.2 → flask_postgresql_audit-1.1.3}/CHANGES.md +4 -0
- {flask_postgresql_audit-1.1.2 → flask_postgresql_audit-1.1.3}/PKG-INFO +1 -1
- {flask_postgresql_audit-1.1.2 → flask_postgresql_audit-1.1.3}/flask_postgresql_audit/__init__.py +1 -1
- {flask_postgresql_audit-1.1.2 → flask_postgresql_audit-1.1.3}/flask_postgresql_audit/alembic/entities.py +10 -0
- {flask_postgresql_audit-1.1.2 → flask_postgresql_audit-1.1.3}/flask_postgresql_audit/alembic/setup.py +1 -0
- flask_postgresql_audit-1.1.3/flask_postgresql_audit/templates/jsonb_diff.sql +42 -0
- {flask_postgresql_audit-1.1.2 → flask_postgresql_audit-1.1.3}/tests/test_operators.py +48 -0
- {flask_postgresql_audit-1.1.2 → flask_postgresql_audit-1.1.3}/.gitignore +0 -0
- {flask_postgresql_audit-1.1.2 → flask_postgresql_audit-1.1.3}/LICENSE +0 -0
- {flask_postgresql_audit-1.1.2 → flask_postgresql_audit-1.1.3}/README.md +0 -0
- {flask_postgresql_audit-1.1.2 → flask_postgresql_audit-1.1.3}/flask_postgresql_audit/alembic/__init__.py +0 -0
- {flask_postgresql_audit-1.1.2 → flask_postgresql_audit-1.1.3}/flask_postgresql_audit/alembic/schema.py +0 -0
- {flask_postgresql_audit-1.1.2 → flask_postgresql_audit-1.1.3}/flask_postgresql_audit/base.py +0 -0
- {flask_postgresql_audit-1.1.2 → flask_postgresql_audit-1.1.3}/flask_postgresql_audit/core.py +0 -0
- {flask_postgresql_audit-1.1.2 → flask_postgresql_audit-1.1.3}/flask_postgresql_audit/extensions/__init__.py +0 -0
- {flask_postgresql_audit-1.1.2 → flask_postgresql_audit-1.1.3}/flask_postgresql_audit/extensions/alembic_utils/__init__.py +0 -0
- {flask_postgresql_audit-1.1.2 → flask_postgresql_audit-1.1.3}/flask_postgresql_audit/extensions/alembic_utils/pg_aggregate.py +0 -0
- {flask_postgresql_audit-1.1.2 → flask_postgresql_audit-1.1.3}/flask_postgresql_audit/extensions/document_staging/__init__.py +0 -0
- {flask_postgresql_audit-1.1.2 → flask_postgresql_audit-1.1.3}/flask_postgresql_audit/extensions/document_staging/enum.py +0 -0
- {flask_postgresql_audit-1.1.2 → flask_postgresql_audit-1.1.3}/flask_postgresql_audit/extensions/document_staging/listener.py +0 -0
- {flask_postgresql_audit-1.1.2 → flask_postgresql_audit-1.1.3}/flask_postgresql_audit/extensions/document_staging/model.py +0 -0
- {flask_postgresql_audit-1.1.2 → flask_postgresql_audit-1.1.3}/flask_postgresql_audit/models.py +0 -0
- {flask_postgresql_audit-1.1.2 → flask_postgresql_audit-1.1.3}/flask_postgresql_audit/templates/audit_trigger_delete.sql +0 -0
- {flask_postgresql_audit-1.1.2 → flask_postgresql_audit-1.1.3}/flask_postgresql_audit/templates/audit_trigger_insert.sql +0 -0
- {flask_postgresql_audit-1.1.2 → flask_postgresql_audit-1.1.3}/flask_postgresql_audit/templates/audit_trigger_update.sql +0 -0
- {flask_postgresql_audit-1.1.2 → flask_postgresql_audit-1.1.3}/flask_postgresql_audit/templates/create_activity.sql +0 -0
- {flask_postgresql_audit-1.1.2 → flask_postgresql_audit-1.1.3}/flask_postgresql_audit/templates/get_pk_values.sql +0 -0
- {flask_postgresql_audit-1.1.2 → flask_postgresql_audit-1.1.3}/flask_postgresql_audit/templates/get_setting.sql +0 -0
- {flask_postgresql_audit-1.1.2 → flask_postgresql_audit-1.1.3}/flask_postgresql_audit/templates/get_table_relid.sql +0 -0
- {flask_postgresql_audit-1.1.2 → flask_postgresql_audit-1.1.3}/flask_postgresql_audit/templates/jsonb_array_subtract.sql +0 -0
- {flask_postgresql_audit-1.1.2 → flask_postgresql_audit-1.1.3}/flask_postgresql_audit/templates/jsonb_subtract.sql +0 -0
- {flask_postgresql_audit-1.1.2 → flask_postgresql_audit-1.1.3}/flask_postgresql_audit/typing.py +0 -0
- {flask_postgresql_audit-1.1.2 → flask_postgresql_audit-1.1.3}/flask_postgresql_audit/utils.py +0 -0
- {flask_postgresql_audit-1.1.2 → flask_postgresql_audit-1.1.3}/pyproject.toml +0 -0
- {flask_postgresql_audit-1.1.2 → flask_postgresql_audit-1.1.3}/tests/__init__.py +0 -0
- {flask_postgresql_audit-1.1.2 → flask_postgresql_audit-1.1.3}/tests/app.py +0 -0
- {flask_postgresql_audit-1.1.2 → flask_postgresql_audit-1.1.3}/tests/conftest.py +0 -0
- {flask_postgresql_audit-1.1.2 → flask_postgresql_audit-1.1.3}/tests/migrations/README +0 -0
- {flask_postgresql_audit-1.1.2 → flask_postgresql_audit-1.1.3}/tests/migrations/alembic.ini +0 -0
- {flask_postgresql_audit-1.1.2 → flask_postgresql_audit-1.1.3}/tests/migrations/env.py +0 -0
- {flask_postgresql_audit-1.1.2 → flask_postgresql_audit-1.1.3}/tests/migrations/script.py.mako +0 -0
- {flask_postgresql_audit-1.1.2 → flask_postgresql_audit-1.1.3}/tests/test_defaults.py +0 -0
- {flask_postgresql_audit-1.1.2 → flask_postgresql_audit-1.1.3}/tests/test_document_staging.py +0 -0
- {flask_postgresql_audit-1.1.2 → flask_postgresql_audit-1.1.3}/tests/test_pg_aggregate.py +0 -0
- {flask_postgresql_audit-1.1.2 → flask_postgresql_audit-1.1.3}/tests/utils.py +0 -0
|
@@ -3,6 +3,10 @@
|
|
|
3
3
|
Here you can see the full list of changes between each Flask-PostgreSQL-Audit
|
|
4
4
|
release.
|
|
5
5
|
|
|
6
|
+
## 1.1.3 (2026-08-21)
|
|
7
|
+
|
|
8
|
+
- Add `jsonb_diff()` function to recursively compute differences across JSONB objects and arrays.
|
|
9
|
+
|
|
6
10
|
## 1.1.2 (2026-08-21)
|
|
7
11
|
|
|
8
12
|
- Add dedicated `jsonb_array_subtract()` function to support set difference operations on JSONB arrays.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: flask-postgresql-audit
|
|
3
|
-
Version: 1.1.
|
|
3
|
+
Version: 1.1.3
|
|
4
4
|
Summary: Versioning and auditing extension for PostgreSQL and SQLAlchemy.
|
|
5
5
|
Project-URL: Homepage, https://github.com/higamigu/flask-postgresql-audit
|
|
6
6
|
Author-email: Higamigu <higamigu@gmail.com>, Konsta Vesterinen <konsta@fastmonkeys.com>
|
|
@@ -90,3 +90,13 @@ def jsonb_array_subtract_factory(**context):
|
|
|
90
90
|
signature="jsonb_array_subtract(arg1 jsonb, arg2 jsonb)",
|
|
91
91
|
definition=sql["definition"],
|
|
92
92
|
)
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def jsonb_diff_factory(**context):
|
|
96
|
+
context.setdefault("jsonb_subtract_join_type", "LEFT")
|
|
97
|
+
sql = parse_template("jsonb_diff.sql", **context)
|
|
98
|
+
return PGFunction(
|
|
99
|
+
schema=context["schema_name"],
|
|
100
|
+
signature="jsonb_diff(arg1 jsonb, arg2 jsonb)",
|
|
101
|
+
definition=sql["definition"],
|
|
102
|
+
)
|
|
@@ -129,6 +129,7 @@ def register_core_entities(audit: "PostgreSQLAudit"):
|
|
|
129
129
|
audit.pg_audit_entities.add(entities.get_setting_factory(**audit.context))
|
|
130
130
|
audit.pg_audit_entities.add(entities.jsonb_subtract_factory(**audit.context))
|
|
131
131
|
audit.pg_audit_entities.add(entities.jsonb_array_subtract_factory(**audit.context))
|
|
132
|
+
audit.pg_audit_entities.add(entities.jsonb_diff_factory(**audit.context))
|
|
132
133
|
audit.pg_audit_entities.add(entities.create_activity_factory(**audit.context))
|
|
133
134
|
|
|
134
135
|
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
CREATE FUNCTION ${schema_prefix}jsonb_diff(arg1 jsonb, arg2 jsonb) RETURNS jsonb AS $$
|
|
2
|
+
SELECT
|
|
3
|
+
CASE
|
|
4
|
+
WHEN jsonb_typeof(arg1) = 'array' AND jsonb_typeof(arg2) = 'array' THEN
|
|
5
|
+
${schema_prefix}jsonb_array_subtract(arg1, arg2)
|
|
6
|
+
WHEN jsonb_typeof(arg1) = 'object' AND jsonb_typeof(arg2) = 'object' THEN
|
|
7
|
+
COALESCE(
|
|
8
|
+
(
|
|
9
|
+
SELECT json_object_agg(
|
|
10
|
+
KEY,
|
|
11
|
+
CASE
|
|
12
|
+
WHEN new_type = 'object' AND old_type = 'object'
|
|
13
|
+
THEN ${schema_prefix}jsonb_diff(new_value, old_value)
|
|
14
|
+
WHEN new_type = 'array' AND old_type = 'array'
|
|
15
|
+
THEN ${schema_prefix}jsonb_diff(new_value, old_value)
|
|
16
|
+
ELSE new_value
|
|
17
|
+
END
|
|
18
|
+
)
|
|
19
|
+
FROM (
|
|
20
|
+
SELECT KEY, VALUE AS new_value, jsonb_typeof(VALUE) AS new_type
|
|
21
|
+
FROM jsonb_each(arg1)
|
|
22
|
+
) AS NEW
|
|
23
|
+
${jsonb_subtract_join_type} OUTER JOIN (
|
|
24
|
+
SELECT KEY, VALUE AS old_value, jsonb_typeof(VALUE) AS old_type
|
|
25
|
+
FROM jsonb_each(arg2)
|
|
26
|
+
) AS OLD
|
|
27
|
+
USING (KEY)
|
|
28
|
+
WHERE new_value IS DISTINCT FROM old_value
|
|
29
|
+
)::jsonb,
|
|
30
|
+
'{}'::jsonb
|
|
31
|
+
)
|
|
32
|
+
WHEN jsonb_typeof(arg1) = 'array' THEN
|
|
33
|
+
${schema_prefix}jsonb_array_subtract(arg1, arg2)
|
|
34
|
+
WHEN jsonb_typeof(arg1) = 'object' AND (arg2 IS NULL OR jsonb_typeof(arg2) != 'object') THEN
|
|
35
|
+
arg1
|
|
36
|
+
WHEN arg1 IS DISTINCT FROM arg2 THEN
|
|
37
|
+
arg1
|
|
38
|
+
ELSE
|
|
39
|
+
NULL
|
|
40
|
+
END
|
|
41
|
+
$$ LANGUAGE SQL;
|
|
42
|
+
|
|
@@ -63,3 +63,51 @@ def test_jsonb_array_subtract(test_client, arg1, arg2, result):
|
|
|
63
63
|
)
|
|
64
64
|
== result
|
|
65
65
|
)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
JSONB_DIFF = "SELECT {schema}jsonb_diff((:new)::jsonb, (:old)::jsonb)"
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
@pytest.mark.parametrize(
|
|
72
|
+
("old", "new", "result"),
|
|
73
|
+
(
|
|
74
|
+
({}, {}, {}),
|
|
75
|
+
({"age": 13}, {"age": 14}, {"age": 14}),
|
|
76
|
+
({"name": "Someone"}, {"name": "Someone"}, {}),
|
|
77
|
+
(
|
|
78
|
+
{"a": {"b": 1, "c": 2}},
|
|
79
|
+
{"a": {"b": 1, "c": 3}},
|
|
80
|
+
{"a": {"c": 3}},
|
|
81
|
+
),
|
|
82
|
+
([2], [1, 2, 3], [1, 3]),
|
|
83
|
+
([1, 2, 3], [1, 2, 3], []),
|
|
84
|
+
(
|
|
85
|
+
{"tags": [2], "name": "a"},
|
|
86
|
+
{"tags": [1, 2, 3], "name": "a"},
|
|
87
|
+
{"tags": [1, 3]},
|
|
88
|
+
),
|
|
89
|
+
(
|
|
90
|
+
{"tags": [1, 2], "name": "a"},
|
|
91
|
+
{"tags": [1, 2], "name": "a"},
|
|
92
|
+
{},
|
|
93
|
+
),
|
|
94
|
+
(
|
|
95
|
+
{"data": {"items": ["b"], "meta": {"v": 1}}},
|
|
96
|
+
{"data": {"items": ["a", "b", "c"], "meta": {"v": 2}}},
|
|
97
|
+
{"data": {"items": ["a", "c"], "meta": {"v": 2}}},
|
|
98
|
+
),
|
|
99
|
+
(
|
|
100
|
+
[{"id": 1}],
|
|
101
|
+
[{"id": 1}, {"id": 2}],
|
|
102
|
+
[{"id": 2}],
|
|
103
|
+
),
|
|
104
|
+
),
|
|
105
|
+
)
|
|
106
|
+
def test_jsonb_diff(test_client, old, new, result):
|
|
107
|
+
assert (
|
|
108
|
+
db.session.scalar(
|
|
109
|
+
text(JSONB_DIFF.format(schema=audit.context["schema_prefix"])),
|
|
110
|
+
{"old": json.dumps(old), "new": json.dumps(new)},
|
|
111
|
+
)
|
|
112
|
+
== result
|
|
113
|
+
)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{flask_postgresql_audit-1.1.2 → flask_postgresql_audit-1.1.3}/flask_postgresql_audit/base.py
RENAMED
|
File without changes
|
{flask_postgresql_audit-1.1.2 → flask_postgresql_audit-1.1.3}/flask_postgresql_audit/core.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{flask_postgresql_audit-1.1.2 → flask_postgresql_audit-1.1.3}/flask_postgresql_audit/models.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{flask_postgresql_audit-1.1.2 → flask_postgresql_audit-1.1.3}/flask_postgresql_audit/typing.py
RENAMED
|
File without changes
|
{flask_postgresql_audit-1.1.2 → flask_postgresql_audit-1.1.3}/flask_postgresql_audit/utils.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{flask_postgresql_audit-1.1.2 → flask_postgresql_audit-1.1.3}/tests/migrations/script.py.mako
RENAMED
|
File without changes
|
|
File without changes
|
{flask_postgresql_audit-1.1.2 → flask_postgresql_audit-1.1.3}/tests/test_document_staging.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|