mirror of
https://github.com/spiral-project/ihatemoney.git
synced 2025-04-29 09:52:36 +02:00
upgrade sqlalchemy-continuum
1.3.10 is needed to remove the patch 1.3.12 is needed for SQLAlchemy 1.4
This commit is contained in:
parent
a14c7c5aaf
commit
1bea93f8a5
3 changed files with 1 additions and 143 deletions
|
@ -21,7 +21,6 @@ from sqlalchemy_continuum.plugins import FlaskPlugin
|
||||||
from werkzeug.security import generate_password_hash
|
from werkzeug.security import generate_password_hash
|
||||||
|
|
||||||
from ihatemoney.currency_convertor import CurrencyConverter
|
from ihatemoney.currency_convertor import CurrencyConverter
|
||||||
from ihatemoney.patch_sqlalchemy_continuum import PatchedBuilder
|
|
||||||
from ihatemoney.utils import get_members, same_bill
|
from ihatemoney.utils import get_members, same_bill
|
||||||
from ihatemoney.versioning import (
|
from ihatemoney.versioning import (
|
||||||
ConditionalVersioningManager,
|
ConditionalVersioningManager,
|
||||||
|
@ -36,9 +35,6 @@ make_versioned(
|
||||||
# Conditionally Disable the versioning based on each
|
# Conditionally Disable the versioning based on each
|
||||||
# project's privacy preferences
|
# project's privacy preferences
|
||||||
tracking_predicate=version_privacy_predicate,
|
tracking_predicate=version_privacy_predicate,
|
||||||
# Patch in a fix to a SQLAchemy-Continuum Bug.
|
|
||||||
# See patch_sqlalchemy_continuum.py
|
|
||||||
builder=PatchedBuilder(),
|
|
||||||
),
|
),
|
||||||
plugins=[
|
plugins=[
|
||||||
FlaskPlugin(
|
FlaskPlugin(
|
||||||
|
|
|
@ -1,138 +0,0 @@
|
||||||
"""
|
|
||||||
A temporary work-around to patch SQLAlchemy-continuum per:
|
|
||||||
https://github.com/kvesteri/sqlalchemy-continuum/pull/242
|
|
||||||
|
|
||||||
Source code reproduced under their license:
|
|
||||||
|
|
||||||
Copyright (c) 2012, Konsta Vesterinen
|
|
||||||
|
|
||||||
All rights reserved.
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
|
||||||
modification, are permitted provided that the following conditions are met:
|
|
||||||
|
|
||||||
* Redistributions of source code must retain the above copyright notice, this
|
|
||||||
list of conditions and the following disclaimer.
|
|
||||||
|
|
||||||
* Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
this list of conditions and the following disclaimer in the documentation
|
|
||||||
and/or other materials provided with the distribution.
|
|
||||||
|
|
||||||
* The names of the contributors may not be used to endorse or promote products
|
|
||||||
derived from this software without specific prior written permission.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY DIRECT,
|
|
||||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
|
||||||
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
||||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
||||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
|
||||||
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
|
||||||
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import sqlalchemy as sa
|
|
||||||
from sqlalchemy_continuum import Operation
|
|
||||||
from sqlalchemy_continuum.builder import Builder
|
|
||||||
from sqlalchemy_continuum.expression_reflector import VersionExpressionReflector
|
|
||||||
from sqlalchemy_continuum.relationship_builder import RelationshipBuilder
|
|
||||||
from sqlalchemy_continuum.utils import adapt_columns, option
|
|
||||||
|
|
||||||
|
|
||||||
class PatchedRelationShipBuilder(RelationshipBuilder):
|
|
||||||
def association_subquery(self, obj):
|
|
||||||
"""
|
|
||||||
Returns an EXISTS clause that checks if an association exists for given
|
|
||||||
SQLAlchemy declarative object. This query is used by
|
|
||||||
many_to_many_criteria method.
|
|
||||||
|
|
||||||
Example query:
|
|
||||||
|
|
||||||
.. code-block:: sql
|
|
||||||
|
|
||||||
EXISTS (
|
|
||||||
SELECT 1
|
|
||||||
FROM article_tag_version
|
|
||||||
WHERE article_id = 3
|
|
||||||
AND tag_id = tags_version.id
|
|
||||||
AND operation_type != 2
|
|
||||||
AND EXISTS (
|
|
||||||
SELECT 1
|
|
||||||
FROM article_tag_version as article_tag_version2
|
|
||||||
WHERE article_tag_version2.tag_id = article_tag_version.tag_id
|
|
||||||
AND article_tag_version2.tx_id <=5
|
|
||||||
AND article_tag_version2.article_id = 3
|
|
||||||
GROUP BY article_tag_version2.tag_id
|
|
||||||
HAVING
|
|
||||||
MAX(article_tag_version2.tx_id) =
|
|
||||||
article_tag_version.tx_id
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
:param obj: SQLAlchemy declarative object
|
|
||||||
"""
|
|
||||||
|
|
||||||
tx_column = option(obj, "transaction_column_name")
|
|
||||||
join_column = self.property.primaryjoin.right.name
|
|
||||||
object_join_column = self.property.primaryjoin.left.name
|
|
||||||
reflector = VersionExpressionReflector(obj, self.property)
|
|
||||||
|
|
||||||
association_table_alias = self.association_version_table.alias()
|
|
||||||
association_cols = [
|
|
||||||
association_table_alias.c[association_col.name]
|
|
||||||
for _, association_col in self.remote_to_association_column_pairs
|
|
||||||
]
|
|
||||||
|
|
||||||
association_exists = sa.exists(
|
|
||||||
sa.select([1])
|
|
||||||
.where(
|
|
||||||
sa.and_(
|
|
||||||
association_table_alias.c[tx_column] <= getattr(obj, tx_column),
|
|
||||||
association_table_alias.c[join_column]
|
|
||||||
== getattr(obj, object_join_column),
|
|
||||||
*[
|
|
||||||
association_col
|
|
||||||
== self.association_version_table.c[association_col.name]
|
|
||||||
for association_col in association_cols
|
|
||||||
],
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.group_by(*association_cols)
|
|
||||||
.having(
|
|
||||||
sa.func.max(association_table_alias.c[tx_column])
|
|
||||||
== self.association_version_table.c[tx_column]
|
|
||||||
)
|
|
||||||
.correlate(self.association_version_table)
|
|
||||||
)
|
|
||||||
return sa.exists(
|
|
||||||
sa.select([1])
|
|
||||||
.where(
|
|
||||||
sa.and_(
|
|
||||||
reflector(self.property.primaryjoin),
|
|
||||||
association_exists,
|
|
||||||
self.association_version_table.c.operation_type != Operation.DELETE,
|
|
||||||
adapt_columns(self.property.secondaryjoin),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.correlate(self.local_cls, self.remote_cls)
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class PatchedBuilder(Builder):
|
|
||||||
def build_relationships(self, version_classes):
|
|
||||||
"""
|
|
||||||
Builds relationships for all version classes.
|
|
||||||
|
|
||||||
:param version_classes: list of generated version classes
|
|
||||||
"""
|
|
||||||
for cls in version_classes:
|
|
||||||
if not self.manager.option(cls, "versioning"):
|
|
||||||
continue
|
|
||||||
|
|
||||||
for prop in sa.inspect(cls).iterate_properties:
|
|
||||||
if prop.key == "versions":
|
|
||||||
continue
|
|
||||||
builder = PatchedRelationShipBuilder(self.manager, cls, prop)
|
|
||||||
builder()
|
|
|
@ -40,7 +40,7 @@ install_requires =
|
||||||
itsdangerous>=2,<3
|
itsdangerous>=2,<3
|
||||||
Jinja2>=3,<4
|
Jinja2>=3,<4
|
||||||
requests>=2.22,<3
|
requests>=2.22,<3
|
||||||
SQLAlchemy-Continuum>=1.3.9,<2
|
SQLAlchemy-Continuum>=1.3.12,<2
|
||||||
SQLAlchemy>=1.3.0,<1.4 # New 1.4 changes API, see #728
|
SQLAlchemy>=1.3.0,<1.4 # New 1.4 changes API, see #728
|
||||||
python-dateutil
|
python-dateutil
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue