|
1 | 1 | from copy import copy
|
2 | 2 |
|
3 | 3 | import sqlalchemy as sa
|
| 4 | +from sqlalchemy.orm.attributes import set_committed_value |
4 | 5 | from sqlalchemy_utils import get_primary_keys, identity
|
5 | 6 | from .operation import Operations
|
6 | 7 | from .utils import (
|
|
11 | 12 | versioned_column_properties
|
12 | 13 | )
|
13 | 14 |
|
14 |
| -from sqlalchemy.dialects import postgresql |
15 |
| -from sqlalchemy.ext.compiler import compiles |
16 |
| -from sqlalchemy.orm.attributes import set_committed_value |
17 |
| -from sqlalchemy.schema import DDLElement |
18 |
| -from sqlalchemy.sql.expression import CTE, exists |
19 |
| - |
20 |
| - |
21 |
| -class Parenthesis(DDLElement): |
22 |
| - def __init__(self, element): |
23 |
| - self.element = element |
24 |
| - |
25 |
| - def __getattr__(self, attr): |
26 |
| - return getattr(self.element, attr) |
27 |
| - |
28 |
| - |
29 |
| -@compiles(Parenthesis) |
30 |
| -def visit_alter_column(element, compiler, **kw): |
31 |
| - return '(%s)' % compiler.process(element.element) |
32 |
| - |
33 |
| - |
34 |
| -def select_or_insert(table, select_values, insert_values, select_criteria): |
35 |
| - criteria = [ |
36 |
| - getattr(table.c, key) == sa.text(str(value)) |
37 |
| - for key, value in select_criteria.items() if value is not None |
38 |
| - ] |
39 |
| - |
40 |
| - select = ( |
41 |
| - sa.select(select_values, from_obj=table) |
42 |
| - .where(sa.and_(*criteria)) |
43 |
| - ) |
44 |
| - insert = ( |
45 |
| - table.insert() |
46 |
| - .from_select( |
47 |
| - insert_values.keys(), |
48 |
| - sa.select(insert_values.values()) |
49 |
| - .where(~ exists(select)) |
50 |
| - ) |
51 |
| - .returning(*map(sa.text, select_values)) |
52 |
| - ) |
53 |
| - insert_cte = CTE( |
54 |
| - Parenthesis(insert), |
55 |
| - name='new_row' |
56 |
| - ) |
57 |
| - query = sa.select(select_values, from_obj=insert_cte).union(select) |
58 |
| - return query |
59 |
| - |
60 | 15 |
|
61 | 16 | class UnitOfWork(object):
|
62 | 17 | def __init__(self, manager):
|
@@ -159,33 +114,35 @@ def create_transaction(self, session):
|
159 | 114 | self.current_transaction = Transaction()
|
160 | 115 |
|
161 | 116 | if self.manager.options['native_versioning']:
|
162 |
| - criteria = {'native_tx_id': sa.func.txid_current()} |
163 |
| - args.update(criteria) |
164 |
| - query = select_or_insert( |
165 |
| - table, |
166 |
| - ['*'], |
167 |
| - args, |
168 |
| - criteria |
169 |
| - ) |
170 |
| - query_string = str(query.compile(dialect=postgresql.dialect())) |
171 |
| - |
172 |
| - values = session.execute(query_string).fetchone() |
173 |
| - for key, value in values.items(): |
174 |
| - set_committed_value(self.current_transaction, key, value) |
175 |
| - |
176 |
| - session.execute( |
177 |
| - ''' |
178 |
| - CREATE TEMP TABLE IF NOT EXISTS continuum_temp_transaction |
179 |
| - (id BIGINT, PRIMARY KEY(id)) |
180 |
| - ON COMMIT DROP |
181 |
| - ''' |
182 |
| - ) |
183 |
| - session.execute(''' |
184 |
| - INSERT INTO continuum_temp_transaction (id) |
185 |
| - SELECT :id WHERE NOT EXISTS |
186 |
| - (SELECT 1 FROM continuum_temp_transaction WHERE id = :id)''', |
187 |
| - {'id': self.current_transaction.id} |
| 117 | + tx_id = ( |
| 118 | + session.execute('SELECT id FROM temporary_transaction') |
| 119 | + .scalar() |
188 | 120 | )
|
| 121 | + if tx_id: |
| 122 | + set_committed_value(self.current_transaction, 'id', tx_id) |
| 123 | + else: |
| 124 | + criteria = {'native_tx_id': sa.func.txid_current()} |
| 125 | + args.update(criteria) |
| 126 | + |
| 127 | + query = table.insert().values(**args) |
| 128 | + |
| 129 | + values = session.execute(query).fetchone() |
| 130 | + for key, value in values.items(): |
| 131 | + set_committed_value(self.current_transaction, key, value) |
| 132 | + |
| 133 | + session.execute( |
| 134 | + ''' |
| 135 | + CREATE TEMP TABLE temporary_transaction |
| 136 | + (id BIGINT, PRIMARY KEY(id)) |
| 137 | + ON COMMIT DROP |
| 138 | + ''' |
| 139 | + ) |
| 140 | + session.execute(''' |
| 141 | + INSERT INTO temporary_transaction (id) |
| 142 | + VALUES (:id) |
| 143 | + ''', |
| 144 | + {'id': self.current_transaction.id} |
| 145 | + ) |
189 | 146 | self.merge_transaction(session, self.current_transaction)
|
190 | 147 | else:
|
191 | 148 | for key, value in args.items():
|
|
0 commit comments