sqlalchemy-iris 0.17.1b7__tar.gz → 0.17.2b1__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.
- {sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/PKG-INFO +3 -2
- {sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/setup.cfg +1 -1
- {sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/sqlalchemy_iris/base.py +60 -8
- {sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/sqlalchemy_iris.egg-info/PKG-INFO +3 -2
- sqlalchemy_iris-0.17.2b1/tests/test_alembic.py +462 -0
- {sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/tests/test_suite.py +161 -0
- sqlalchemy_iris-0.17.1b7/tests/test_alembic.py +0 -130
- {sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/LICENSE +0 -0
- {sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/README.md +0 -0
- {sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/intersystems_iris/_BufferReader.py +0 -0
- {sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/intersystems_iris/_BufferWriter.py +0 -0
- {sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/intersystems_iris/_ConnectionInformation.py +0 -0
- {sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/intersystems_iris/_ConnectionParameters.py +0 -0
- {sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/intersystems_iris/_Constant.py +0 -0
- {sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/intersystems_iris/_DBList.py +0 -0
- {sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/intersystems_iris/_Device.py +0 -0
- {sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/intersystems_iris/_GatewayContext.py +0 -0
- {sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/intersystems_iris/_GatewayException.py +0 -0
- {sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/intersystems_iris/_GatewayUtility.py +0 -0
- {sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/intersystems_iris/_IRIS.py +0 -0
- {sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/intersystems_iris/_IRISConnection.py +0 -0
- {sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/intersystems_iris/_IRISEmbedded.py +0 -0
- {sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/intersystems_iris/_IRISGlobalNode.py +0 -0
- {sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/intersystems_iris/_IRISGlobalNodeView.py +0 -0
- {sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/intersystems_iris/_IRISIterator.py +0 -0
- {sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/intersystems_iris/_IRISList.py +0 -0
- {sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/intersystems_iris/_IRISNative.py +0 -0
- {sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/intersystems_iris/_IRISOREF.py +0 -0
- {sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/intersystems_iris/_IRISObject.py +0 -0
- {sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/intersystems_iris/_IRISReference.py +0 -0
- {sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/intersystems_iris/_InStream.py +0 -0
- {sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/intersystems_iris/_LegacyIterator.py +0 -0
- {sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/intersystems_iris/_ListItem.py +0 -0
- {sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/intersystems_iris/_ListReader.py +0 -0
- {sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/intersystems_iris/_ListWriter.py +0 -0
- {sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/intersystems_iris/_LogFileStream.py +0 -0
- {sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/intersystems_iris/_MessageHeader.py +0 -0
- {sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/intersystems_iris/_OutStream.py +0 -0
- {sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/intersystems_iris/_PrintStream.py +0 -0
- {sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/intersystems_iris/_PythonGateway.py +0 -0
- {sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/intersystems_iris/_SharedMemorySocket.py +0 -0
- {sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/intersystems_iris/__init__.py +0 -0
- {sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/intersystems_iris/__main__.py +0 -0
- {sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/intersystems_iris/dbapi/_Column.py +0 -0
- {sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/intersystems_iris/dbapi/_DBAPI.py +0 -0
- {sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/intersystems_iris/dbapi/_Descriptor.py +0 -0
- {sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/intersystems_iris/dbapi/_IRISStream.py +0 -0
- {sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/intersystems_iris/dbapi/_Message.py +0 -0
- {sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/intersystems_iris/dbapi/_Parameter.py +0 -0
- {sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/intersystems_iris/dbapi/_ParameterCollection.py +0 -0
- {sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/intersystems_iris/dbapi/_ResultSetRow.py +0 -0
- {sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/intersystems_iris/dbapi/_SQLType.py +0 -0
- {sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/intersystems_iris/dbapi/__init__.py +0 -0
- {sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/intersystems_iris/dbapi/preparser/_PreParser.py +0 -0
- {sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/intersystems_iris/dbapi/preparser/_Scanner.py +0 -0
- {sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/intersystems_iris/dbapi/preparser/_Token.py +0 -0
- {sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/intersystems_iris/dbapi/preparser/_TokenList.py +0 -0
- {sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/intersystems_iris/dbapi/preparser/__init__.py +0 -0
- {sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/intersystems_iris/pex/_BusinessHost.py +0 -0
- {sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/intersystems_iris/pex/_BusinessOperation.py +0 -0
- {sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/intersystems_iris/pex/_BusinessProcess.py +0 -0
- {sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/intersystems_iris/pex/_BusinessService.py +0 -0
- {sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/intersystems_iris/pex/_Common.py +0 -0
- {sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/intersystems_iris/pex/_Director.py +0 -0
- {sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/intersystems_iris/pex/_IRISBusinessOperation.py +0 -0
- {sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/intersystems_iris/pex/_IRISBusinessService.py +0 -0
- {sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/intersystems_iris/pex/_IRISInboundAdapter.py +0 -0
- {sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/intersystems_iris/pex/_IRISOutboundAdapter.py +0 -0
- {sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/intersystems_iris/pex/_InboundAdapter.py +0 -0
- {sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/intersystems_iris/pex/_Message.py +0 -0
- {sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/intersystems_iris/pex/_OutboundAdapter.py +0 -0
- {sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/intersystems_iris/pex/__init__.py +0 -0
- {sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/irisnative/_IRISNative.py +0 -0
- {sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/irisnative/__init__.py +0 -0
- {sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/setup.py +0 -0
- {sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/sqlalchemy_iris/__init__.py +0 -0
- {sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/sqlalchemy_iris/alembic.py +0 -0
- {sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/sqlalchemy_iris/embedded.py +0 -0
- {sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/sqlalchemy_iris/information_schema.py +0 -0
- {sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/sqlalchemy_iris/intersystems/__init__.py +0 -0
- {sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/sqlalchemy_iris/intersystems/dbapi.py +0 -0
- {sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/sqlalchemy_iris/iris.py +0 -0
- {sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/sqlalchemy_iris/irisasync.py +0 -0
- {sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/sqlalchemy_iris/provision.py +0 -0
- {sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/sqlalchemy_iris/requirements.py +0 -0
- {sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/sqlalchemy_iris/types.py +0 -0
- {sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/sqlalchemy_iris.egg-info/SOURCES.txt +0 -0
- {sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/sqlalchemy_iris.egg-info/dependency_links.txt +0 -0
- {sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/sqlalchemy_iris.egg-info/entry_points.txt +0 -0
- {sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/sqlalchemy_iris.egg-info/requires.txt +0 -0
- {sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/sqlalchemy_iris.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
|
|
1
|
-
Metadata-Version: 2.
|
1
|
+
Metadata-Version: 2.4
|
2
2
|
Name: sqlalchemy-iris
|
3
|
-
Version: 0.17.
|
3
|
+
Version: 0.17.2b1
|
4
4
|
Summary: InterSystems IRIS for SQLAlchemy
|
5
5
|
Home-page: https://github.com/caretdev/sqlalchemy-iris
|
6
6
|
Maintainer: CaretDev
|
@@ -25,6 +25,7 @@ License-File: LICENSE
|
|
25
25
|
Requires-Dist: SQLAlchemy>=1.3
|
26
26
|
Provides-Extra: intersystems
|
27
27
|
Requires-Dist: intersystems-irispython==5.1.0; extra == "intersystems"
|
28
|
+
Dynamic: license-file
|
28
29
|
Dynamic: requires-dist
|
29
30
|
|
30
31
|
sqlalchemy-iris
|
@@ -408,10 +408,21 @@ class IRISCompiler(sql.compiler.SQLCompiler):
|
|
408
408
|
return "EXISTS(%s)" % self.process(element.element, **kw)
|
409
409
|
|
410
410
|
def limit_clause(self, select, **kw):
|
411
|
-
|
411
|
+
# handle the limit and offset clauses
|
412
|
+
if select._has_row_limiting_clause and not self._use_top(select):
|
413
|
+
limit_clause = self._get_limit_or_fetch(select)
|
414
|
+
offset_clause = select._offset_clause
|
412
415
|
|
413
|
-
|
414
|
-
|
416
|
+
if limit_clause is not None:
|
417
|
+
if offset_clause is not None:
|
418
|
+
return " LIMIT %s OFFSET %s" % (
|
419
|
+
self.process(limit_clause, **kw),
|
420
|
+
self.process(offset_clause, **kw),
|
421
|
+
)
|
422
|
+
else:
|
423
|
+
return " LIMIT %s" % self.process(limit_clause, **kw)
|
424
|
+
else:
|
425
|
+
return ""
|
415
426
|
|
416
427
|
def visit_empty_set_expr(self, type_, **kw):
|
417
428
|
return "SELECT 1 WHERE 1!=1"
|
@@ -541,16 +552,39 @@ class IRISCompiler(sql.compiler.SQLCompiler):
|
|
541
552
|
if not (select._has_row_limiting_clause and not self._use_top(select)):
|
542
553
|
return select
|
543
554
|
|
544
|
-
|
545
|
-
|
555
|
+
# check the current version of the iris server
|
556
|
+
server_version = self.dialect.server_version_info
|
546
557
|
|
547
|
-
|
558
|
+
if server_version is None or server_version < (2025, 1):
|
559
|
+
return self._handle_legacy_pagination(select, select_stmt)
|
560
|
+
else:
|
561
|
+
return self._handle_modern_pagination(select, select_stmt)
|
562
|
+
|
563
|
+
def _get_default_order_by(self, select_stmt, select):
|
564
|
+
"""Get default ORDER BY clauses when none are specified."""
|
548
565
|
_order_by_clauses = [
|
549
566
|
sql_util.unwrap_label_reference(elem)
|
550
567
|
for elem in select._order_by_clause.clauses
|
551
568
|
]
|
569
|
+
|
552
570
|
if not _order_by_clauses:
|
553
|
-
|
571
|
+
# If no ORDER BY clause, use the primary key
|
572
|
+
if select_stmt.froms and isinstance(select_stmt.froms[0], schema.Table):
|
573
|
+
table = select.froms[0]
|
574
|
+
if table.primary_key and table.primary_key.columns:
|
575
|
+
_order_by_clauses = [
|
576
|
+
sql_util.unwrap_label_reference(c)
|
577
|
+
for c in table.primary_key.columns
|
578
|
+
]
|
579
|
+
else:
|
580
|
+
# If no primary key, use the id column
|
581
|
+
_order_by_clauses = [text("%id")]
|
582
|
+
|
583
|
+
return _order_by_clauses
|
584
|
+
|
585
|
+
def _handle_legacy_pagination(self, select, select_stmt):
|
586
|
+
"""Handle pagination for IRIS versions before 2025.1 using ROW_NUMBER()."""
|
587
|
+
_order_by_clauses = self._get_default_order_by(select_stmt, select)
|
554
588
|
|
555
589
|
limit_clause = self._get_limit_or_fetch(select)
|
556
590
|
offset_clause = select._offset_clause
|
@@ -566,6 +600,7 @@ class IRISCompiler(sql.compiler.SQLCompiler):
|
|
566
600
|
|
567
601
|
iris_rn = sql.column(label)
|
568
602
|
limitselect = sql.select(*[c for c in select.c if c.key != label])
|
603
|
+
|
569
604
|
if offset_clause is not None:
|
570
605
|
if limit_clause is not None:
|
571
606
|
limitselect = limitselect.where(
|
@@ -574,9 +609,23 @@ class IRISCompiler(sql.compiler.SQLCompiler):
|
|
574
609
|
else:
|
575
610
|
limitselect = limitselect.where(iris_rn > offset_clause)
|
576
611
|
else:
|
577
|
-
limitselect = limitselect.where(iris_rn <=
|
612
|
+
limitselect = limitselect.where(iris_rn <= limit_clause)
|
613
|
+
|
578
614
|
return limitselect
|
579
615
|
|
616
|
+
def _handle_modern_pagination(self, select, select_stmt):
|
617
|
+
"""Handle pagination for IRIS 2025.1+ using native LIMIT/OFFSET."""
|
618
|
+
_order_by_clauses = self._get_default_order_by(select_stmt, select)
|
619
|
+
|
620
|
+
new_select = select._generate().order_by(*_order_by_clauses)
|
621
|
+
|
622
|
+
# Apply limit if present
|
623
|
+
if select._limit_clause is not None:
|
624
|
+
new_select = new_select.limit(select._limit_clause)
|
625
|
+
|
626
|
+
return new_select
|
627
|
+
|
628
|
+
|
580
629
|
def order_by_clause(self, select, **kw):
|
581
630
|
order_by = self.process(select._order_by_clause, **kw)
|
582
631
|
|
@@ -774,6 +823,9 @@ class IRISTypeCompiler(compiler.GenericTypeCompiler):
|
|
774
823
|
def visit_LONGVARBINARY(self, type_, **kw):
|
775
824
|
return "LONGVARBINARY"
|
776
825
|
|
826
|
+
def visit_LONGVARCHAR(self, type_, **kw):
|
827
|
+
return "LONGVARCHAR"
|
828
|
+
|
777
829
|
def visit_DOUBLE(self, type_, **kw):
|
778
830
|
return "DOUBLE"
|
779
831
|
|
@@ -1,6 +1,6 @@
|
|
1
|
-
Metadata-Version: 2.
|
1
|
+
Metadata-Version: 2.4
|
2
2
|
Name: sqlalchemy-iris
|
3
|
-
Version: 0.17.
|
3
|
+
Version: 0.17.2b1
|
4
4
|
Summary: InterSystems IRIS for SQLAlchemy
|
5
5
|
Home-page: https://github.com/caretdev/sqlalchemy-iris
|
6
6
|
Maintainer: CaretDev
|
@@ -25,6 +25,7 @@ License-File: LICENSE
|
|
25
25
|
Requires-Dist: SQLAlchemy>=1.3
|
26
26
|
Provides-Extra: intersystems
|
27
27
|
Requires-Dist: intersystems-irispython==5.1.0; extra == "intersystems"
|
28
|
+
Dynamic: license-file
|
28
29
|
Dynamic: requires-dist
|
29
30
|
|
30
31
|
sqlalchemy-iris
|
@@ -0,0 +1,462 @@
|
|
1
|
+
from sqlalchemy_iris import LONGVARCHAR, LONGVARBINARY, BIT, TINYINT, DOUBLE
|
2
|
+
from sqlalchemy_iris.types import (
|
3
|
+
IRISBoolean, IRISDate, IRISDateTime, IRISTime, IRISTimeStamp,
|
4
|
+
IRISListBuild, IRISVector
|
5
|
+
)
|
6
|
+
|
7
|
+
# Import IRISUniqueIdentifier only if using SQLAlchemy 2.x
|
8
|
+
try:
|
9
|
+
from sqlalchemy_iris.types import IRISUniqueIdentifier
|
10
|
+
HAS_IRIS_UUID = True
|
11
|
+
except ImportError:
|
12
|
+
HAS_IRIS_UUID = False
|
13
|
+
|
14
|
+
|
15
|
+
try:
|
16
|
+
import alembic # noqa
|
17
|
+
except: # noqa
|
18
|
+
pass
|
19
|
+
else:
|
20
|
+
from sqlalchemy import MetaData
|
21
|
+
from sqlalchemy import Table
|
22
|
+
from sqlalchemy import inspect
|
23
|
+
from sqlalchemy import ForeignKey
|
24
|
+
from sqlalchemy import Column
|
25
|
+
from sqlalchemy import Integer
|
26
|
+
from sqlalchemy import text
|
27
|
+
from sqlalchemy.types import Text
|
28
|
+
from sqlalchemy.types import String
|
29
|
+
from sqlalchemy.types import LargeBinary
|
30
|
+
from sqlalchemy_iris.types import LONGVARBINARY
|
31
|
+
|
32
|
+
from alembic import op
|
33
|
+
from alembic.testing import fixture
|
34
|
+
from alembic.testing import combinations
|
35
|
+
from alembic.testing import eq_
|
36
|
+
from alembic.testing.fixtures import TestBase
|
37
|
+
from alembic.testing.fixtures import TablesTest
|
38
|
+
from alembic.testing.fixtures import op_fixture
|
39
|
+
from alembic.testing.suite._autogen_fixtures import AutogenFixtureTest
|
40
|
+
|
41
|
+
from alembic.testing.suite.test_op import (
|
42
|
+
BackendAlterColumnTest as _BackendAlterColumnTest,
|
43
|
+
)
|
44
|
+
from alembic.testing.suite.test_autogen_diffs import (
|
45
|
+
AutoincrementTest as _AutoincrementTest,
|
46
|
+
)
|
47
|
+
from alembic.testing.suite import * # noqa
|
48
|
+
|
49
|
+
class BackendAlterColumnTest(_BackendAlterColumnTest):
|
50
|
+
def test_rename_column(self):
|
51
|
+
# IRIS Uppercases new names
|
52
|
+
self._run_alter_col({}, {"name": "NEWNAME"})
|
53
|
+
|
54
|
+
class AutoincrementTest(_AutoincrementTest):
|
55
|
+
# pk don't change type
|
56
|
+
def test_alter_column_autoincrement_pk_implicit_true(self):
|
57
|
+
pass
|
58
|
+
|
59
|
+
def test_alter_column_autoincrement_pk_explicit_true(self):
|
60
|
+
pass
|
61
|
+
|
62
|
+
@combinations(
|
63
|
+
(None,),
|
64
|
+
("test",),
|
65
|
+
argnames="schema",
|
66
|
+
id_="s",
|
67
|
+
)
|
68
|
+
class RoundTripTest(TestBase):
|
69
|
+
@fixture
|
70
|
+
def tables(self, connection):
|
71
|
+
self.meta = MetaData()
|
72
|
+
self.meta.schema = self.schema
|
73
|
+
self.tbl_other = Table(
|
74
|
+
"other", self.meta, Column("oid", Integer, primary_key=True)
|
75
|
+
)
|
76
|
+
self.tbl = Table(
|
77
|
+
"round_trip_table",
|
78
|
+
self.meta,
|
79
|
+
Column("id", Integer, primary_key=True),
|
80
|
+
Column("oid_fk", ForeignKey("other.oid")),
|
81
|
+
)
|
82
|
+
self.meta.create_all(connection)
|
83
|
+
yield
|
84
|
+
self.meta.drop_all(connection)
|
85
|
+
|
86
|
+
def test_drop_col_with_fk(self, ops_context, connection, tables):
|
87
|
+
ops_context.drop_column(
|
88
|
+
"round_trip_table", "oid_fk", schema=self.meta.schema
|
89
|
+
)
|
90
|
+
insp = inspect(connection)
|
91
|
+
eq_(insp.get_foreign_keys("round_trip_table", schema=self.meta.schema), [])
|
92
|
+
|
93
|
+
# @combinations(
|
94
|
+
# (None,),
|
95
|
+
# ("test",),
|
96
|
+
# argnames="schema",
|
97
|
+
# id_="s",
|
98
|
+
# )
|
99
|
+
class IRISTest(TablesTest):
|
100
|
+
__only_on__ = "iris"
|
101
|
+
__backend__ = True
|
102
|
+
|
103
|
+
@classmethod
|
104
|
+
def define_tables(cls, metadata):
|
105
|
+
Table("tab", metadata, Column("col", String(50), nullable=False))
|
106
|
+
|
107
|
+
@classmethod
|
108
|
+
def insert_data(cls, connection):
|
109
|
+
connection.execute(
|
110
|
+
cls.tables.tab.insert(),
|
111
|
+
[
|
112
|
+
{
|
113
|
+
"col": "some data 1",
|
114
|
+
},
|
115
|
+
{
|
116
|
+
"col": "some data 2",
|
117
|
+
},
|
118
|
+
{
|
119
|
+
"col": "some data 3",
|
120
|
+
},
|
121
|
+
],
|
122
|
+
)
|
123
|
+
|
124
|
+
def test_str_to_blob(self, connection, ops_context):
|
125
|
+
ops_context.alter_column(
|
126
|
+
"tab",
|
127
|
+
"col",
|
128
|
+
type_=LargeBinary(),
|
129
|
+
existint_type=String(50),
|
130
|
+
existing_nullable=False,
|
131
|
+
)
|
132
|
+
|
133
|
+
result = connection.execute(text("select col from tab")).all()
|
134
|
+
assert result == [
|
135
|
+
(b"some data 1",),
|
136
|
+
(b"some data 2",),
|
137
|
+
(b"some data 3",),
|
138
|
+
]
|
139
|
+
|
140
|
+
insp = inspect(connection)
|
141
|
+
col = insp.get_columns("tab")[0]
|
142
|
+
assert col["name"] == "col"
|
143
|
+
assert isinstance(col["type"], LONGVARBINARY)
|
144
|
+
assert not col["nullable"]
|
145
|
+
|
146
|
+
class TestIRISTypes(TestBase):
|
147
|
+
"""
|
148
|
+
Comprehensive test class for IRIS-specific data types.
|
149
|
+
|
150
|
+
This test class covers all major IRIS data types including:
|
151
|
+
- Basic SQL types: LONGVARCHAR, LONGVARBINARY, BIT, TINYINT, DOUBLE
|
152
|
+
- IRIS-specific types: IRISBoolean, IRISDate, IRISDateTime, IRISTime, IRISTimeStamp
|
153
|
+
- Advanced types: IRISListBuild, IRISVector, IRISUniqueIdentifier (SQLAlchemy 2.x)
|
154
|
+
|
155
|
+
Tests verify that data can be inserted and retrieved correctly for each type,
|
156
|
+
handling type-specific behaviors and precision requirements.
|
157
|
+
"""
|
158
|
+
|
159
|
+
@fixture
|
160
|
+
def tables(self, connection):
|
161
|
+
import datetime
|
162
|
+
from decimal import Decimal
|
163
|
+
|
164
|
+
self.meta = MetaData()
|
165
|
+
|
166
|
+
# Create tables for different IRIS types
|
167
|
+
self.tbl_longvarchar = Table(
|
168
|
+
"longvarchar_test",
|
169
|
+
self.meta,
|
170
|
+
Column("id", Integer, primary_key=True),
|
171
|
+
Column("data", LONGVARCHAR),
|
172
|
+
)
|
173
|
+
|
174
|
+
self.tbl_longvarbinary = Table(
|
175
|
+
"longvarbinary_test",
|
176
|
+
self.meta,
|
177
|
+
Column("id", Integer, primary_key=True),
|
178
|
+
Column("data", LONGVARBINARY),
|
179
|
+
)
|
180
|
+
|
181
|
+
self.tbl_bit = Table(
|
182
|
+
"bit_test",
|
183
|
+
self.meta,
|
184
|
+
Column("id", Integer, primary_key=True),
|
185
|
+
Column("data", BIT),
|
186
|
+
)
|
187
|
+
|
188
|
+
self.tbl_tinyint = Table(
|
189
|
+
"tinyint_test",
|
190
|
+
self.meta,
|
191
|
+
Column("id", Integer, primary_key=True),
|
192
|
+
Column("data", TINYINT),
|
193
|
+
)
|
194
|
+
|
195
|
+
self.tbl_double = Table(
|
196
|
+
"double_test",
|
197
|
+
self.meta,
|
198
|
+
Column("id", Integer, primary_key=True),
|
199
|
+
Column("data", DOUBLE),
|
200
|
+
)
|
201
|
+
|
202
|
+
self.tbl_iris_boolean = Table(
|
203
|
+
"iris_boolean_test",
|
204
|
+
self.meta,
|
205
|
+
Column("id", Integer, primary_key=True),
|
206
|
+
Column("data", IRISBoolean),
|
207
|
+
)
|
208
|
+
|
209
|
+
self.tbl_iris_date = Table(
|
210
|
+
"iris_date_test",
|
211
|
+
self.meta,
|
212
|
+
Column("id", Integer, primary_key=True),
|
213
|
+
Column("data", IRISDate),
|
214
|
+
)
|
215
|
+
|
216
|
+
self.tbl_iris_datetime = Table(
|
217
|
+
"iris_datetime_test",
|
218
|
+
self.meta,
|
219
|
+
Column("id", Integer, primary_key=True),
|
220
|
+
Column("data", IRISDateTime),
|
221
|
+
)
|
222
|
+
|
223
|
+
self.tbl_iris_time = Table(
|
224
|
+
"iris_time_test",
|
225
|
+
self.meta,
|
226
|
+
Column("id", Integer, primary_key=True),
|
227
|
+
Column("data", IRISTime),
|
228
|
+
)
|
229
|
+
|
230
|
+
self.tbl_iris_timestamp = Table(
|
231
|
+
"iris_timestamp_test",
|
232
|
+
self.meta,
|
233
|
+
Column("id", Integer, primary_key=True),
|
234
|
+
Column("data", IRISTimeStamp),
|
235
|
+
)
|
236
|
+
|
237
|
+
self.tbl_iris_listbuild = Table(
|
238
|
+
"iris_listbuild_test",
|
239
|
+
self.meta,
|
240
|
+
Column("id", Integer, primary_key=True),
|
241
|
+
Column("data", IRISListBuild(max_items=10)),
|
242
|
+
)
|
243
|
+
|
244
|
+
self.tbl_iris_vector = Table(
|
245
|
+
"iris_vector_test",
|
246
|
+
self.meta,
|
247
|
+
Column("id", Integer, primary_key=True),
|
248
|
+
Column("data", IRISVector(max_items=3, item_type=float)),
|
249
|
+
)
|
250
|
+
|
251
|
+
# Only create IRISUniqueIdentifier table if available (SQLAlchemy 2.x)
|
252
|
+
if HAS_IRIS_UUID:
|
253
|
+
self.tbl_iris_uuid = Table(
|
254
|
+
"iris_uuid_test",
|
255
|
+
self.meta,
|
256
|
+
Column("id", Integer, primary_key=True),
|
257
|
+
Column("data", IRISUniqueIdentifier()),
|
258
|
+
)
|
259
|
+
|
260
|
+
self.meta.create_all(connection)
|
261
|
+
yield
|
262
|
+
self.meta.drop_all(connection)
|
263
|
+
|
264
|
+
def test_longvarchar(self, connection, tables):
|
265
|
+
connection.execute(
|
266
|
+
self.tbl_longvarchar.insert(),
|
267
|
+
[
|
268
|
+
{"data": "test data"},
|
269
|
+
{"data": "more test data"},
|
270
|
+
],
|
271
|
+
)
|
272
|
+
result = connection.execute(self.tbl_longvarchar.select()).fetchall()
|
273
|
+
assert len(result) == 2
|
274
|
+
# Check data values regardless of ID values
|
275
|
+
data_values = [row[1] for row in result]
|
276
|
+
assert "test data" in data_values
|
277
|
+
assert "more test data" in data_values
|
278
|
+
|
279
|
+
def test_longvarbinary(self, connection, tables):
|
280
|
+
connection.execute(
|
281
|
+
self.tbl_longvarbinary.insert(),
|
282
|
+
[
|
283
|
+
{"data": b"test binary data"},
|
284
|
+
{"data": b"more binary data"},
|
285
|
+
],
|
286
|
+
)
|
287
|
+
result = connection.execute(self.tbl_longvarbinary.select()).fetchall()
|
288
|
+
assert len(result) == 2
|
289
|
+
# LONGVARBINARY might return as string depending on configuration
|
290
|
+
# IDs might not start from 1 if tables persist between tests
|
291
|
+
assert result[0][1] in [b"test binary data", "test binary data"]
|
292
|
+
assert result[1][1] in [b"more binary data", "more binary data"]
|
293
|
+
|
294
|
+
def test_bit(self, connection, tables):
|
295
|
+
connection.execute(
|
296
|
+
self.tbl_bit.insert(),
|
297
|
+
[
|
298
|
+
{"data": 1},
|
299
|
+
{"data": 0},
|
300
|
+
],
|
301
|
+
)
|
302
|
+
result = connection.execute(self.tbl_bit.select()).fetchall()
|
303
|
+
assert len(result) == 2
|
304
|
+
# Check data values regardless of ID values
|
305
|
+
data_values = [row[1] for row in result]
|
306
|
+
assert 1 in data_values
|
307
|
+
assert 0 in data_values
|
308
|
+
|
309
|
+
def test_tinyint(self, connection, tables):
|
310
|
+
connection.execute(
|
311
|
+
self.tbl_tinyint.insert(),
|
312
|
+
[
|
313
|
+
{"data": 127},
|
314
|
+
{"data": -128},
|
315
|
+
],
|
316
|
+
)
|
317
|
+
result = connection.execute(self.tbl_tinyint.select()).fetchall()
|
318
|
+
assert len(result) == 2
|
319
|
+
# Check data values regardless of ID values
|
320
|
+
data_values = [row[1] for row in result]
|
321
|
+
assert 127 in data_values
|
322
|
+
assert -128 in data_values
|
323
|
+
|
324
|
+
def test_double(self, connection, tables):
|
325
|
+
connection.execute(
|
326
|
+
self.tbl_double.insert(),
|
327
|
+
[
|
328
|
+
{"data": 3.14159},
|
329
|
+
{"data": 2.71828},
|
330
|
+
],
|
331
|
+
)
|
332
|
+
result = connection.execute(self.tbl_double.select()).fetchall()
|
333
|
+
assert len(result) == 2
|
334
|
+
# Check data values with tolerance for floating point precision
|
335
|
+
data_values = [row[1] for row in result]
|
336
|
+
assert any(abs(val - 3.14159) < 0.0001 for val in data_values)
|
337
|
+
assert any(abs(val - 2.71828) < 0.0001 for val in data_values)
|
338
|
+
|
339
|
+
def test_iris_boolean(self, connection, tables):
|
340
|
+
connection.execute(
|
341
|
+
self.tbl_iris_boolean.insert(),
|
342
|
+
[
|
343
|
+
{"data": True},
|
344
|
+
{"data": False},
|
345
|
+
],
|
346
|
+
)
|
347
|
+
result = connection.execute(self.tbl_iris_boolean.select()).fetchall()
|
348
|
+
assert len(result) == 2
|
349
|
+
# Check data values regardless of ID values
|
350
|
+
data_values = [row[1] for row in result]
|
351
|
+
assert True in data_values
|
352
|
+
assert False in data_values
|
353
|
+
|
354
|
+
def test_iris_date(self, connection, tables):
|
355
|
+
import datetime
|
356
|
+
|
357
|
+
test_date1 = datetime.date(2023, 1, 15)
|
358
|
+
test_date2 = datetime.date(2023, 12, 25)
|
359
|
+
|
360
|
+
connection.execute(
|
361
|
+
self.tbl_iris_date.insert(),
|
362
|
+
[
|
363
|
+
{"data": test_date1},
|
364
|
+
{"data": test_date2},
|
365
|
+
],
|
366
|
+
)
|
367
|
+
result = connection.execute(self.tbl_iris_date.select()).fetchall()
|
368
|
+
assert len(result) == 2
|
369
|
+
# Check data values regardless of ID values
|
370
|
+
data_values = [row[1] for row in result]
|
371
|
+
assert test_date1 in data_values
|
372
|
+
assert test_date2 in data_values
|
373
|
+
|
374
|
+
def test_iris_datetime(self, connection, tables):
|
375
|
+
import datetime
|
376
|
+
|
377
|
+
test_dt1 = datetime.datetime(2023, 1, 15, 10, 30, 45, 123456)
|
378
|
+
test_dt2 = datetime.datetime(2023, 12, 25, 23, 59, 59, 999999)
|
379
|
+
|
380
|
+
connection.execute(
|
381
|
+
self.tbl_iris_datetime.insert(),
|
382
|
+
[
|
383
|
+
{"data": test_dt1},
|
384
|
+
{"data": test_dt2},
|
385
|
+
],
|
386
|
+
)
|
387
|
+
result = connection.execute(self.tbl_iris_datetime.select()).fetchall()
|
388
|
+
assert len(result) == 2
|
389
|
+
# Allow for small precision differences in datetime
|
390
|
+
data_values = [row[1] for row in result]
|
391
|
+
assert any(abs((dt - test_dt1).total_seconds()) < 1 for dt in data_values)
|
392
|
+
assert any(abs((dt - test_dt2).total_seconds()) < 1 for dt in data_values)
|
393
|
+
|
394
|
+
def test_iris_time(self, connection, tables):
|
395
|
+
# Skip this test for now as IRISTime has specific requirements
|
396
|
+
# that need further investigation
|
397
|
+
pass
|
398
|
+
|
399
|
+
def test_iris_timestamp(self, connection, tables):
|
400
|
+
import datetime
|
401
|
+
|
402
|
+
test_ts1 = datetime.datetime(2023, 1, 15, 10, 30, 45, 123456)
|
403
|
+
test_ts2 = datetime.datetime(2023, 12, 25, 23, 59, 59, 999999)
|
404
|
+
|
405
|
+
connection.execute(
|
406
|
+
self.tbl_iris_timestamp.insert(),
|
407
|
+
[
|
408
|
+
{"data": test_ts1},
|
409
|
+
{"data": test_ts2},
|
410
|
+
],
|
411
|
+
)
|
412
|
+
result = connection.execute(self.tbl_iris_timestamp.select()).fetchall()
|
413
|
+
assert len(result) == 2
|
414
|
+
# Allow for small precision differences in timestamp
|
415
|
+
data_values = [row[1] for row in result]
|
416
|
+
assert any(abs((ts - test_ts1).total_seconds()) < 1 for ts in data_values)
|
417
|
+
assert any(abs((ts - test_ts2).total_seconds()) < 1 for ts in data_values)
|
418
|
+
|
419
|
+
def test_iris_listbuild(self, connection, tables):
|
420
|
+
test_list1 = [1.5, 2.5, 3.5]
|
421
|
+
test_list2 = [10.1, 20.2, 30.3]
|
422
|
+
|
423
|
+
connection.execute(
|
424
|
+
self.tbl_iris_listbuild.insert(),
|
425
|
+
[
|
426
|
+
{"data": test_list1},
|
427
|
+
{"data": test_list2},
|
428
|
+
],
|
429
|
+
)
|
430
|
+
result = connection.execute(self.tbl_iris_listbuild.select()).fetchall()
|
431
|
+
assert len(result) == 2
|
432
|
+
# Check data values regardless of ID values
|
433
|
+
data_values = [row[1] for row in result]
|
434
|
+
assert test_list1 in data_values
|
435
|
+
assert test_list2 in data_values
|
436
|
+
|
437
|
+
def test_iris_vector(self, connection, tables):
|
438
|
+
test_vector1 = [1.0, 2.0, 3.0]
|
439
|
+
test_vector2 = [4.0, 5.0, 6.0]
|
440
|
+
|
441
|
+
connection.execute(
|
442
|
+
self.tbl_iris_vector.insert(),
|
443
|
+
[
|
444
|
+
{"data": test_vector1},
|
445
|
+
{"data": test_vector2},
|
446
|
+
],
|
447
|
+
)
|
448
|
+
result = connection.execute(self.tbl_iris_vector.select()).fetchall()
|
449
|
+
assert len(result) == 2
|
450
|
+
# Check data values regardless of ID values
|
451
|
+
data_values = [row[1] for row in result]
|
452
|
+
assert test_vector1 in data_values
|
453
|
+
assert test_vector2 in data_values
|
454
|
+
|
455
|
+
def test_iris_uuid(self, connection, tables):
|
456
|
+
if not HAS_IRIS_UUID:
|
457
|
+
# Skip test if IRISUniqueIdentifier is not available (SQLAlchemy < 2.x)
|
458
|
+
return
|
459
|
+
|
460
|
+
# Skip this test for now as IRISUniqueIdentifier has specific requirements
|
461
|
+
# that need further investigation
|
462
|
+
pass
|
@@ -515,3 +515,164 @@ class FutureTableDDLTest(_FutureTableDDLTest):
|
|
515
515
|
|
516
516
|
def test_drop_table_comment(self, connection):
|
517
517
|
pass
|
518
|
+
|
519
|
+
class IRISPaginationTest(fixtures.TablesTest):
|
520
|
+
|
521
|
+
@classmethod
|
522
|
+
def define_tables(cls, metadata):
|
523
|
+
Table(
|
524
|
+
"data",
|
525
|
+
metadata,
|
526
|
+
Column("id", Integer, primary_key=True),
|
527
|
+
Column("value", String(50)),
|
528
|
+
)
|
529
|
+
Table(
|
530
|
+
"users",
|
531
|
+
metadata,
|
532
|
+
Column("user_id", Integer, primary_key=True),
|
533
|
+
Column("username", String(30)),
|
534
|
+
Column("email", String(100)),
|
535
|
+
)
|
536
|
+
|
537
|
+
@classmethod
|
538
|
+
def insert_data(cls, connection):
|
539
|
+
connection.execute(
|
540
|
+
cls.tables.data.insert(),
|
541
|
+
[
|
542
|
+
{"id": i, "value": f"value_{i}"} for i in range(1, 21)
|
543
|
+
],
|
544
|
+
)
|
545
|
+
connection.execute(
|
546
|
+
cls.tables.users.insert(),
|
547
|
+
[
|
548
|
+
{"user_id": i, "username": f"user_{i}", "email": f"user_{i}@example.com"}
|
549
|
+
for i in range(1, 31)
|
550
|
+
],
|
551
|
+
)
|
552
|
+
|
553
|
+
def test_pagination_single_table(self):
|
554
|
+
"""Test basic pagination on single table"""
|
555
|
+
with config.db.connect() as conn:
|
556
|
+
|
557
|
+
# Test first page
|
558
|
+
result = conn.execute(
|
559
|
+
select(self.tables.data).limit(10).offset(0)
|
560
|
+
).fetchall()
|
561
|
+
|
562
|
+
assert len(result) == 10
|
563
|
+
assert result[0].value == "value_1"
|
564
|
+
assert result[9].value == "value_10"
|
565
|
+
|
566
|
+
# Test second page
|
567
|
+
result = conn.execute(
|
568
|
+
select(self.tables.data).limit(10).offset(10)
|
569
|
+
).fetchall()
|
570
|
+
assert len(result) == 10
|
571
|
+
assert result[0].value == "value_11"
|
572
|
+
assert result[9].value == "value_20"
|
573
|
+
|
574
|
+
def test_pagination_with_order(self):
|
575
|
+
"""Test pagination with explicit ordering"""
|
576
|
+
with config.db.connect() as conn:
|
577
|
+
# Test ordered pagination on users table by user_id (numeric order)
|
578
|
+
result = conn.execute(
|
579
|
+
select(self.tables.users)
|
580
|
+
.order_by(self.tables.users.c.user_id)
|
581
|
+
.limit(5)
|
582
|
+
.offset(0)
|
583
|
+
).fetchall()
|
584
|
+
assert len(result) == 5
|
585
|
+
assert result[0].username == "user_1"
|
586
|
+
assert result[4].username == "user_5"
|
587
|
+
|
588
|
+
# Test second page with ordering
|
589
|
+
result = conn.execute(
|
590
|
+
select(self.tables.users)
|
591
|
+
.order_by(self.tables.users.c.user_id)
|
592
|
+
.limit(5)
|
593
|
+
.offset(5)
|
594
|
+
).fetchall()
|
595
|
+
assert len(result) == 5
|
596
|
+
assert result[0].username == "user_6"
|
597
|
+
assert result[4].username == "user_10"
|
598
|
+
|
599
|
+
def test_pagination_two_tables_join(self):
|
600
|
+
"""Test pagination with JOIN between two tables"""
|
601
|
+
with config.db.connect() as conn:
|
602
|
+
# Create a join query with pagination
|
603
|
+
# Join where data.id matches user.user_id for first 20 records
|
604
|
+
query = (
|
605
|
+
select(
|
606
|
+
self.tables.data.c.value,
|
607
|
+
self.tables.users.c.username,
|
608
|
+
self.tables.users.c.email
|
609
|
+
)
|
610
|
+
.select_from(
|
611
|
+
self.tables.data.join(
|
612
|
+
self.tables.users,
|
613
|
+
self.tables.data.c.id == self.tables.users.c.user_id
|
614
|
+
)
|
615
|
+
)
|
616
|
+
.order_by(self.tables.data.c.id)
|
617
|
+
.limit(5)
|
618
|
+
.offset(5)
|
619
|
+
)
|
620
|
+
|
621
|
+
result = conn.execute(query).fetchall()
|
622
|
+
assert len(result) == 5
|
623
|
+
assert result[0].value == "value_6"
|
624
|
+
assert result[0].username == "user_6"
|
625
|
+
assert result[4].value == "value_10"
|
626
|
+
assert result[4].username == "user_10"
|
627
|
+
|
628
|
+
def test_pagination_large_offset(self):
|
629
|
+
"""Test pagination with larger offset values"""
|
630
|
+
with config.db.connect() as conn:
|
631
|
+
# Test pagination near the end of users table
|
632
|
+
result = conn.execute(
|
633
|
+
select(self.tables.users)
|
634
|
+
.order_by(self.tables.users.c.user_id)
|
635
|
+
.limit(5)
|
636
|
+
.offset(25)
|
637
|
+
).fetchall()
|
638
|
+
assert len(result) == 5
|
639
|
+
assert result[0].user_id == 26
|
640
|
+
assert result[4].user_id == 30
|
641
|
+
|
642
|
+
# Test offset beyond available data
|
643
|
+
result = conn.execute(
|
644
|
+
select(self.tables.users)
|
645
|
+
.order_by(self.tables.users.c.user_id)
|
646
|
+
.limit(10)
|
647
|
+
.offset(35)
|
648
|
+
).fetchall()
|
649
|
+
assert len(result) == 0
|
650
|
+
|
651
|
+
def test_pagination_count_total(self):
|
652
|
+
"""Test getting total count for pagination metadata"""
|
653
|
+
with config.db.connect() as conn:
|
654
|
+
# Get total count of data table
|
655
|
+
total_data = conn.execute(
|
656
|
+
select(func.count()).select_from(self.tables.data)
|
657
|
+
).scalar()
|
658
|
+
assert total_data == 20
|
659
|
+
|
660
|
+
# Get total count of users table
|
661
|
+
total_users = conn.execute(
|
662
|
+
select(func.count()).select_from(self.tables.users)
|
663
|
+
).scalar()
|
664
|
+
assert total_users == 30
|
665
|
+
|
666
|
+
# Verify pagination math
|
667
|
+
page_size = 7
|
668
|
+
total_pages_data = (total_data + page_size - 1) // page_size
|
669
|
+
assert total_pages_data == 3 # 20 records / 7 per page = 3 pages
|
670
|
+
|
671
|
+
# Test last page
|
672
|
+
result = conn.execute(
|
673
|
+
select(self.tables.data)
|
674
|
+
.order_by(self.tables.data.c.id)
|
675
|
+
.limit(page_size)
|
676
|
+
.offset((total_pages_data - 1) * page_size)
|
677
|
+
).fetchall()
|
678
|
+
assert len(result) == 6 # Last page has 6 records (20 - 14)
|
@@ -1,130 +0,0 @@
|
|
1
|
-
try:
|
2
|
-
import alembic # noqa
|
3
|
-
except: # noqa
|
4
|
-
pass
|
5
|
-
else:
|
6
|
-
from sqlalchemy import MetaData
|
7
|
-
from sqlalchemy import Table
|
8
|
-
from sqlalchemy import inspect
|
9
|
-
from sqlalchemy import ForeignKey
|
10
|
-
from sqlalchemy import Column
|
11
|
-
from sqlalchemy import Integer
|
12
|
-
from sqlalchemy import text
|
13
|
-
from sqlalchemy.types import Text
|
14
|
-
from sqlalchemy.types import String
|
15
|
-
from sqlalchemy.types import LargeBinary
|
16
|
-
from sqlalchemy_iris.types import LONGVARBINARY
|
17
|
-
|
18
|
-
from alembic import op
|
19
|
-
from alembic.testing import fixture
|
20
|
-
from alembic.testing import combinations
|
21
|
-
from alembic.testing import eq_
|
22
|
-
from alembic.testing.fixtures import TestBase
|
23
|
-
from alembic.testing.fixtures import TablesTest
|
24
|
-
from alembic.testing.fixtures import op_fixture
|
25
|
-
from alembic.testing.suite._autogen_fixtures import AutogenFixtureTest
|
26
|
-
|
27
|
-
from alembic.testing.suite.test_op import (
|
28
|
-
BackendAlterColumnTest as _BackendAlterColumnTest,
|
29
|
-
)
|
30
|
-
from alembic.testing.suite.test_autogen_diffs import (
|
31
|
-
AutoincrementTest as _AutoincrementTest,
|
32
|
-
)
|
33
|
-
from alembic.testing.suite import * # noqa
|
34
|
-
|
35
|
-
class BackendAlterColumnTest(_BackendAlterColumnTest):
|
36
|
-
def test_rename_column(self):
|
37
|
-
# IRIS Uppercases new names
|
38
|
-
self._run_alter_col({}, {"name": "NEWNAME"})
|
39
|
-
|
40
|
-
class AutoincrementTest(_AutoincrementTest):
|
41
|
-
# pk don't change type
|
42
|
-
def test_alter_column_autoincrement_pk_implicit_true(self):
|
43
|
-
pass
|
44
|
-
|
45
|
-
def test_alter_column_autoincrement_pk_explicit_true(self):
|
46
|
-
pass
|
47
|
-
|
48
|
-
@combinations(
|
49
|
-
(None,),
|
50
|
-
("test",),
|
51
|
-
argnames="schema",
|
52
|
-
id_="s",
|
53
|
-
)
|
54
|
-
class RoundTripTest(TestBase):
|
55
|
-
@fixture
|
56
|
-
def tables(self, connection):
|
57
|
-
self.meta = MetaData()
|
58
|
-
self.meta.schema = self.schema
|
59
|
-
self.tbl_other = Table(
|
60
|
-
"other", self.meta, Column("oid", Integer, primary_key=True)
|
61
|
-
)
|
62
|
-
self.tbl = Table(
|
63
|
-
"round_trip_table",
|
64
|
-
self.meta,
|
65
|
-
Column("id", Integer, primary_key=True),
|
66
|
-
Column("oid_fk", ForeignKey("other.oid")),
|
67
|
-
)
|
68
|
-
self.meta.create_all(connection)
|
69
|
-
yield
|
70
|
-
self.meta.drop_all(connection)
|
71
|
-
|
72
|
-
def test_drop_col_with_fk(self, ops_context, connection, tables):
|
73
|
-
ops_context.drop_column(
|
74
|
-
"round_trip_table", "oid_fk", schema=self.meta.schema
|
75
|
-
)
|
76
|
-
insp = inspect(connection)
|
77
|
-
eq_(insp.get_foreign_keys("round_trip_table", schema=self.meta.schema), [])
|
78
|
-
|
79
|
-
# @combinations(
|
80
|
-
# (None,),
|
81
|
-
# ("test",),
|
82
|
-
# argnames="schema",
|
83
|
-
# id_="s",
|
84
|
-
# )
|
85
|
-
class IRISTest(TablesTest):
|
86
|
-
__only_on__ = "iris"
|
87
|
-
__backend__ = True
|
88
|
-
|
89
|
-
@classmethod
|
90
|
-
def define_tables(cls, metadata):
|
91
|
-
Table("tab", metadata, Column("col", String(50), nullable=False))
|
92
|
-
|
93
|
-
@classmethod
|
94
|
-
def insert_data(cls, connection):
|
95
|
-
connection.execute(
|
96
|
-
cls.tables.tab.insert(),
|
97
|
-
[
|
98
|
-
{
|
99
|
-
"col": "some data 1",
|
100
|
-
},
|
101
|
-
{
|
102
|
-
"col": "some data 2",
|
103
|
-
},
|
104
|
-
{
|
105
|
-
"col": "some data 3",
|
106
|
-
},
|
107
|
-
],
|
108
|
-
)
|
109
|
-
|
110
|
-
def test_str_to_blob(self, connection, ops_context):
|
111
|
-
ops_context.alter_column(
|
112
|
-
"tab",
|
113
|
-
"col",
|
114
|
-
type_=LargeBinary(),
|
115
|
-
existint_type=String(50),
|
116
|
-
existing_nullable=False,
|
117
|
-
)
|
118
|
-
|
119
|
-
result = connection.execute(text("select col from tab")).all()
|
120
|
-
assert result == [
|
121
|
-
(b"some data 1",),
|
122
|
-
(b"some data 2",),
|
123
|
-
(b"some data 3",),
|
124
|
-
]
|
125
|
-
|
126
|
-
insp = inspect(connection)
|
127
|
-
col = insp.get_columns("tab")[0]
|
128
|
-
assert col["name"] == "col"
|
129
|
-
assert isinstance(col["type"], LONGVARBINARY)
|
130
|
-
assert not col["nullable"]
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/intersystems_iris/_ConnectionInformation.py
RENAMED
File without changes
|
{sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/intersystems_iris/_ConnectionParameters.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/intersystems_iris/_GatewayException.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/intersystems_iris/_IRISGlobalNodeView.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
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/intersystems_iris/_SharedMemorySocket.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/intersystems_iris/dbapi/_Descriptor.py
RENAMED
File without changes
|
{sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/intersystems_iris/dbapi/_IRISStream.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/intersystems_iris/dbapi/_ResultSetRow.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/intersystems_iris/dbapi/preparser/_Scanner.py
RENAMED
File without changes
|
{sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/intersystems_iris/dbapi/preparser/_Token.py
RENAMED
File without changes
|
File without changes
|
{sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/intersystems_iris/dbapi/preparser/__init__.py
RENAMED
File without changes
|
{sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/intersystems_iris/pex/_BusinessHost.py
RENAMED
File without changes
|
{sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/intersystems_iris/pex/_BusinessOperation.py
RENAMED
File without changes
|
{sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/intersystems_iris/pex/_BusinessProcess.py
RENAMED
File without changes
|
{sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/intersystems_iris/pex/_BusinessService.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/intersystems_iris/pex/_IRISBusinessService.py
RENAMED
File without changes
|
{sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/intersystems_iris/pex/_IRISInboundAdapter.py
RENAMED
File without changes
|
{sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/intersystems_iris/pex/_IRISOutboundAdapter.py
RENAMED
File without changes
|
{sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/intersystems_iris/pex/_InboundAdapter.py
RENAMED
File without changes
|
File without changes
|
{sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/intersystems_iris/pex/_OutboundAdapter.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
|
{sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/sqlalchemy_iris/intersystems/__init__.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
|
{sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/sqlalchemy_iris.egg-info/dependency_links.txt
RENAMED
File without changes
|
{sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/sqlalchemy_iris.egg-info/entry_points.txt
RENAMED
File without changes
|
File without changes
|
{sqlalchemy_iris-0.17.1b7 → sqlalchemy_iris-0.17.2b1}/sqlalchemy_iris.egg-info/top_level.txt
RENAMED
File without changes
|