sqlobject 3.13.1__py2.py3-none-any.whl
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.
- sqlobject/__init__.py +15 -0
- sqlobject/__version__.py +8 -0
- sqlobject/boundattributes.py +124 -0
- sqlobject/cache.py +376 -0
- sqlobject/classregistry.py +138 -0
- sqlobject/col.py +2187 -0
- sqlobject/compat.py +59 -0
- sqlobject/conftest.py +64 -0
- sqlobject/constraints.py +77 -0
- sqlobject/converters.py +278 -0
- sqlobject/dbconnection.py +1137 -0
- sqlobject/dberrors.py +54 -0
- sqlobject/declarative.py +211 -0
- sqlobject/events.py +365 -0
- sqlobject/firebird/__init__.py +8 -0
- sqlobject/firebird/firebirdconnection.py +463 -0
- sqlobject/include/__init__.py +1 -0
- sqlobject/include/hashcol.py +109 -0
- sqlobject/include/tests/__init__.py +1 -0
- sqlobject/include/tests/test_hashcol.py +84 -0
- sqlobject/index.py +189 -0
- sqlobject/inheritance/__init__.py +551 -0
- sqlobject/inheritance/iteration.py +106 -0
- sqlobject/inheritance/tests/__init__.py +1 -0
- sqlobject/inheritance/tests/test_aggregates.py +23 -0
- sqlobject/inheritance/tests/test_asdict.py +48 -0
- sqlobject/inheritance/tests/test_deep_inheritance.py +114 -0
- sqlobject/inheritance/tests/test_destroy_cascade.py +23 -0
- sqlobject/inheritance/tests/test_foreignKey.py +94 -0
- sqlobject/inheritance/tests/test_indexes.py +42 -0
- sqlobject/inheritance/tests/test_inheritance.py +164 -0
- sqlobject/inheritance/tests/test_inheritance_tree.py +50 -0
- sqlobject/joins.py +656 -0
- sqlobject/main.py +1880 -0
- sqlobject/manager/__init__.py +1 -0
- sqlobject/manager/command.py +1309 -0
- sqlobject/maxdb/__init__.py +8 -0
- sqlobject/maxdb/maxdbconnection.py +320 -0
- sqlobject/maxdb/readme.txt +27 -0
- sqlobject/mssql/__init__.py +8 -0
- sqlobject/mssql/mssqlconnection.py +417 -0
- sqlobject/mysql/__init__.py +8 -0
- sqlobject/mysql/mysqlconnection.py +562 -0
- sqlobject/postgres/__init__.py +8 -0
- sqlobject/postgres/pgconnection.py +619 -0
- sqlobject/sqlbuilder.py +1655 -0
- sqlobject/sqlite/__init__.py +8 -0
- sqlobject/sqlite/sqliteconnection.py +418 -0
- sqlobject/sresults.py +377 -0
- sqlobject/styles.py +174 -0
- sqlobject/sybase/__init__.py +8 -0
- sqlobject/sybase/sybaseconnection.py +183 -0
- sqlobject/tests/__init__.py +1 -0
- sqlobject/tests/dbtest.py +363 -0
- sqlobject/tests/test_ForeignKey.py +133 -0
- sqlobject/tests/test_ForeignKey_cascade.py +150 -0
- sqlobject/tests/test_NoneValuedResultItem.py +33 -0
- sqlobject/tests/test_SQLMultipleJoin.py +65 -0
- sqlobject/tests/test_SQLRelatedJoin.py +114 -0
- sqlobject/tests/test_SingleJoin.py +30 -0
- sqlobject/tests/test_aggregates.py +75 -0
- sqlobject/tests/test_aliases.py +49 -0
- sqlobject/tests/test_asdict.py +18 -0
- sqlobject/tests/test_auto.py +218 -0
- sqlobject/tests/test_basic.py +359 -0
- sqlobject/tests/test_blob.py +34 -0
- sqlobject/tests/test_boundattributes.py +67 -0
- sqlobject/tests/test_cache.py +57 -0
- sqlobject/tests/test_class_hash.py +22 -0
- sqlobject/tests/test_columns_order.py +18 -0
- sqlobject/tests/test_combining_joins.py +47 -0
- sqlobject/tests/test_comparison.py +24 -0
- sqlobject/tests/test_compat.py +10 -0
- sqlobject/tests/test_complex_sorting.py +77 -0
- sqlobject/tests/test_constraints.py +43 -0
- sqlobject/tests/test_converters.py +276 -0
- sqlobject/tests/test_create_drop.py +29 -0
- sqlobject/tests/test_csvexport.py +101 -0
- sqlobject/tests/test_csvimport.py +21 -0
- sqlobject/tests/test_cyclic_reference.py +55 -0
- sqlobject/tests/test_datetime.py +171 -0
- sqlobject/tests/test_dbconnection.py +17 -0
- sqlobject/tests/test_decimal.py +63 -0
- sqlobject/tests/test_declarative.py +83 -0
- sqlobject/tests/test_default_style.py +65 -0
- sqlobject/tests/test_delete.py +74 -0
- sqlobject/tests/test_distinct.py +36 -0
- sqlobject/tests/test_empty.py +22 -0
- sqlobject/tests/test_enum.py +75 -0
- sqlobject/tests/test_events.py +142 -0
- sqlobject/tests/test_exceptions.py +40 -0
- sqlobject/tests/test_expire.py +29 -0
- sqlobject/tests/test_groupBy.py +45 -0
- sqlobject/tests/test_identity.py +29 -0
- sqlobject/tests/test_indexes.py +100 -0
- sqlobject/tests/test_inheritance.py +35 -0
- sqlobject/tests/test_joins.py +160 -0
- sqlobject/tests/test_joins_conditional.py +143 -0
- sqlobject/tests/test_jsonbcol.py +53 -0
- sqlobject/tests/test_jsoncol.py +56 -0
- sqlobject/tests/test_lazy.py +165 -0
- sqlobject/tests/test_md5.py +13 -0
- sqlobject/tests/test_mysql.py +50 -0
- sqlobject/tests/test_new_joins.py +165 -0
- sqlobject/tests/test_parse_uri.py +147 -0
- sqlobject/tests/test_paste.py +92 -0
- sqlobject/tests/test_perConnection.py +20 -0
- sqlobject/tests/test_pickle.py +42 -0
- sqlobject/tests/test_picklecol.py +44 -0
- sqlobject/tests/test_postgres.py +82 -0
- sqlobject/tests/test_reparent_sqlmeta.py +33 -0
- sqlobject/tests/test_schema.py +30 -0
- sqlobject/tests/test_select.py +218 -0
- sqlobject/tests/test_select_through.py +63 -0
- sqlobject/tests/test_setters.py +23 -0
- sqlobject/tests/test_slice.py +59 -0
- sqlobject/tests/test_sorting.py +80 -0
- sqlobject/tests/test_sqlbuilder.py +134 -0
- sqlobject/tests/test_sqlbuilder_dbspecific.py +66 -0
- sqlobject/tests/test_sqlbuilder_importproxy.py +55 -0
- sqlobject/tests/test_sqlbuilder_joins_instances.py +90 -0
- sqlobject/tests/test_sqlite.py +160 -0
- sqlobject/tests/test_sqlmeta_idName.py +52 -0
- sqlobject/tests/test_sqlobject_admin.py +38 -0
- sqlobject/tests/test_string_id.py +79 -0
- sqlobject/tests/test_style.py +36 -0
- sqlobject/tests/test_subqueries.py +142 -0
- sqlobject/tests/test_transactions.py +122 -0
- sqlobject/tests/test_unicode.py +84 -0
- sqlobject/tests/test_uuidcol.py +40 -0
- sqlobject/tests/test_validation.py +125 -0
- sqlobject/tests/test_views.py +159 -0
- sqlobject/util/__init__.py +1 -0
- sqlobject/util/csvexport.py +210 -0
- sqlobject/util/csvimport.py +366 -0
- sqlobject/util/moduleloader.py +35 -0
- sqlobject/util/threadinglocal.py +6 -0
- sqlobject/versioning/__init__.py +120 -0
- sqlobject/versioning/test/__init__.py +0 -0
- sqlobject/versioning/test/test_version.py +183 -0
- sqlobject/views.py +151 -0
- sqlobject/wsgi_middleware.py +109 -0
- sqlobject-3.13.1.data/scripts/sqlobject-admin +36 -0
- sqlobject-3.13.1.data/scripts/sqlobject-convertOldURI +19 -0
- sqlobject-3.13.1.dist-info/METADATA +177 -0
- sqlobject-3.13.1.dist-info/RECORD +149 -0
- sqlobject-3.13.1.dist-info/WHEEL +6 -0
- sqlobject-3.13.1.dist-info/entry_points.txt +4 -0
- sqlobject-3.13.1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
from sqlobject import SQLObject
|
|
3
|
+
from sqlobject.tests.dbtest import setupClass, supports
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class EmptyClass(SQLObject):
|
|
7
|
+
|
|
8
|
+
pass
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def test_empty():
|
|
12
|
+
if not supports('emptyTable'):
|
|
13
|
+
pytest.skip("emptyTable isn't supported")
|
|
14
|
+
setupClass(EmptyClass)
|
|
15
|
+
e1 = EmptyClass()
|
|
16
|
+
e2 = EmptyClass()
|
|
17
|
+
assert e1 != e2
|
|
18
|
+
assert e1.id != e2.id
|
|
19
|
+
assert e1 in list(EmptyClass.select())
|
|
20
|
+
assert e2 in list(EmptyClass.select())
|
|
21
|
+
e1.destroySelf()
|
|
22
|
+
assert list(EmptyClass.select()) == [e2]
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
from sqlobject import EnumCol, SQLObject, UnicodeCol
|
|
2
|
+
from sqlobject.col import validators
|
|
3
|
+
from sqlobject.tests.dbtest import raises, setupClass
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
########################################
|
|
7
|
+
# Enum test
|
|
8
|
+
########################################
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class Enum1(SQLObject):
|
|
12
|
+
|
|
13
|
+
cl = EnumCol(enumValues=['a', 'bcd', 'e'])
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def testBad():
|
|
17
|
+
setupClass(Enum1)
|
|
18
|
+
for _l in ['a', 'bcd', 'a', 'e']:
|
|
19
|
+
Enum1(cl=_l)
|
|
20
|
+
raises(
|
|
21
|
+
(Enum1._connection.module.IntegrityError,
|
|
22
|
+
Enum1._connection.module.ProgrammingError,
|
|
23
|
+
validators.Invalid),
|
|
24
|
+
Enum1, cl='b')
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class EnumWithNone(SQLObject):
|
|
28
|
+
|
|
29
|
+
cl = EnumCol(enumValues=['a', 'bcd', 'e', None])
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def testNone():
|
|
33
|
+
setupClass(EnumWithNone)
|
|
34
|
+
for _l in [None, 'a', 'bcd', 'a', 'e', None]:
|
|
35
|
+
e = EnumWithNone(cl=_l)
|
|
36
|
+
assert e.cl == _l
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class EnumWithDefaultNone(SQLObject):
|
|
40
|
+
|
|
41
|
+
cl = EnumCol(enumValues=['a', 'bcd', 'e', None], default=None)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def testDefaultNone():
|
|
45
|
+
setupClass(EnumWithDefaultNone)
|
|
46
|
+
|
|
47
|
+
e = EnumWithDefaultNone()
|
|
48
|
+
assert e.cl is None
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class EnumWithDefaultOther(SQLObject):
|
|
52
|
+
|
|
53
|
+
cl = EnumCol(enumValues=['a', 'bcd', 'e', None], default='a')
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def testDefaultOther():
|
|
57
|
+
setupClass(EnumWithDefaultOther)
|
|
58
|
+
|
|
59
|
+
e = EnumWithDefaultOther()
|
|
60
|
+
assert e.cl == 'a'
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
class EnumUnicode(SQLObject):
|
|
64
|
+
|
|
65
|
+
n = UnicodeCol()
|
|
66
|
+
cl = EnumCol(enumValues=['a', 'b'])
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def testUnicode():
|
|
70
|
+
setupClass(EnumUnicode)
|
|
71
|
+
|
|
72
|
+
EnumUnicode(n=u'a', cl='a')
|
|
73
|
+
EnumUnicode(n=u'b', cl=u'b')
|
|
74
|
+
EnumUnicode(n=u'\u201c', cl='a')
|
|
75
|
+
EnumUnicode(n=u'\u201c', cl=u'b')
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
from __future__ import print_function
|
|
2
|
+
|
|
3
|
+
from sqlobject import IntCol, SQLObject, StringCol, events
|
|
4
|
+
from sqlobject.inheritance import InheritableSQLObject
|
|
5
|
+
from sqlobject.tests.dbtest import setupClass
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class EventTester(SQLObject):
|
|
9
|
+
name = StringCol()
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def make_watcher():
|
|
13
|
+
log = []
|
|
14
|
+
|
|
15
|
+
def watch(*args):
|
|
16
|
+
log.append(args)
|
|
17
|
+
|
|
18
|
+
watch.log = log
|
|
19
|
+
return watch
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def make_listen(signal, cls=None):
|
|
23
|
+
if cls is None:
|
|
24
|
+
cls = EventTester
|
|
25
|
+
watcher = make_watcher()
|
|
26
|
+
events.listen(watcher, cls, signal)
|
|
27
|
+
return watcher
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def test_create():
|
|
31
|
+
watcher = make_listen(events.ClassCreateSignal)
|
|
32
|
+
|
|
33
|
+
class EventTesterSub1(EventTester):
|
|
34
|
+
pass
|
|
35
|
+
|
|
36
|
+
class EventTesterSub2(EventTesterSub1):
|
|
37
|
+
pass
|
|
38
|
+
|
|
39
|
+
assert len(watcher.log) == 2
|
|
40
|
+
assert len(watcher.log[0]) == 5
|
|
41
|
+
assert watcher.log[0][0] == 'EventTesterSub1'
|
|
42
|
+
assert watcher.log[0][1] == (EventTester,)
|
|
43
|
+
assert isinstance(watcher.log[0][2], dict)
|
|
44
|
+
assert isinstance(watcher.log[0][3], list)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def test_row_create():
|
|
48
|
+
setupClass(EventTester)
|
|
49
|
+
watcher = make_listen(events.RowCreateSignal)
|
|
50
|
+
row1 = EventTester(name='foo')
|
|
51
|
+
row2 = EventTester(name='bar')
|
|
52
|
+
assert len(watcher.log) == 2
|
|
53
|
+
assert watcher.log == [
|
|
54
|
+
(row1, {'name': 'foo'}, []),
|
|
55
|
+
(row2, {'name': 'bar'}, [])]
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def test_row_destroy():
|
|
59
|
+
setupClass(EventTester)
|
|
60
|
+
watcher = make_listen(events.RowDestroySignal)
|
|
61
|
+
f = EventTester(name='foo')
|
|
62
|
+
assert not watcher.log
|
|
63
|
+
f.destroySelf()
|
|
64
|
+
assert watcher.log == [(f, [])]
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def test_row_destroyed():
|
|
68
|
+
setupClass(EventTester)
|
|
69
|
+
watcher = make_listen(events.RowDestroyedSignal)
|
|
70
|
+
f = EventTester(name='foo')
|
|
71
|
+
assert not watcher.log
|
|
72
|
+
f.destroySelf()
|
|
73
|
+
assert watcher.log == [(f, [])]
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def test_row_update():
|
|
77
|
+
setupClass(EventTester)
|
|
78
|
+
watcher = make_listen(events.RowUpdateSignal)
|
|
79
|
+
f = EventTester(name='bar')
|
|
80
|
+
assert not watcher.log
|
|
81
|
+
f.name = 'bar2'
|
|
82
|
+
f.set(name='bar3')
|
|
83
|
+
assert watcher.log == [
|
|
84
|
+
(f, {'name': 'bar2'}),
|
|
85
|
+
(f, {'name': 'bar3'})]
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def test_row_updated():
|
|
89
|
+
setupClass(EventTester)
|
|
90
|
+
watcher = make_listen(events.RowUpdatedSignal)
|
|
91
|
+
f = EventTester(name='bar')
|
|
92
|
+
assert not watcher.log
|
|
93
|
+
f.name = 'bar2'
|
|
94
|
+
f.set(name='bar3')
|
|
95
|
+
assert watcher.log == [(f, []), (f, [])]
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def test_add_column():
|
|
99
|
+
setupClass(EventTester)
|
|
100
|
+
watcher = make_listen(events.AddColumnSignal)
|
|
101
|
+
events.summarize_events_by_sender()
|
|
102
|
+
|
|
103
|
+
class NewEventTester(EventTester):
|
|
104
|
+
name2 = StringCol()
|
|
105
|
+
|
|
106
|
+
expect = (
|
|
107
|
+
NewEventTester, None,
|
|
108
|
+
'name2', NewEventTester.sqlmeta.columnDefinitions['name2'],
|
|
109
|
+
False, [])
|
|
110
|
+
print(zip(watcher.log[1], expect))
|
|
111
|
+
assert watcher.log[1] == expect
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
class InheritableEventTestA(InheritableSQLObject):
|
|
115
|
+
a = IntCol()
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
class InheritableEventTestB(InheritableEventTestA):
|
|
119
|
+
b = IntCol()
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
class InheritableEventTestC(InheritableEventTestB):
|
|
123
|
+
c = IntCol()
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def _query(instance):
|
|
127
|
+
row = InheritableEventTestA.get(instance.id)
|
|
128
|
+
assert isinstance(row, InheritableEventTestC)
|
|
129
|
+
assert row.c == 3
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def _signal(instance, kwargs, postfuncs):
|
|
133
|
+
postfuncs.append(_query)
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def test_inheritance_row_created():
|
|
137
|
+
setupClass([InheritableEventTestA, InheritableEventTestB,
|
|
138
|
+
InheritableEventTestC])
|
|
139
|
+
|
|
140
|
+
events.listen(_signal, InheritableEventTestA, events.RowCreatedSignal)
|
|
141
|
+
|
|
142
|
+
InheritableEventTestC(a=1, b=2, c=3)
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
from sqlobject import SQLObject, StringCol
|
|
3
|
+
from sqlobject.dberrors import DatabaseError, DuplicateEntryError, \
|
|
4
|
+
OperationalError, ProgrammingError
|
|
5
|
+
from sqlobject.tests.dbtest import getConnection, raises, setupClass, supports
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
########################################
|
|
9
|
+
# Table aliases and self-joins
|
|
10
|
+
########################################
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class SOTestException(SQLObject):
|
|
14
|
+
name = StringCol(unique=True, length=100)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class SOTestExceptionWithNonexistingTable(SQLObject):
|
|
18
|
+
pass
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def test_exceptions():
|
|
22
|
+
if not supports("exceptions"):
|
|
23
|
+
pytest.skip("exceptions aren't supported")
|
|
24
|
+
setupClass(SOTestException)
|
|
25
|
+
SOTestException(name="test")
|
|
26
|
+
raises(DuplicateEntryError, SOTestException, name="test")
|
|
27
|
+
|
|
28
|
+
connection = getConnection()
|
|
29
|
+
SOTestExceptionWithNonexistingTable.setConnection(connection)
|
|
30
|
+
try:
|
|
31
|
+
list(SOTestExceptionWithNonexistingTable.select())
|
|
32
|
+
except ProgrammingError as e:
|
|
33
|
+
assert e.args[0].code in (1146, '42P01')
|
|
34
|
+
except OperationalError:
|
|
35
|
+
assert connection.dbName == 'sqlite'
|
|
36
|
+
except DatabaseError:
|
|
37
|
+
assert connection.dbName == 'postgres' \
|
|
38
|
+
and connection.driver == 'pg8000'
|
|
39
|
+
else:
|
|
40
|
+
assert False, "DID NOT RAISE"
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
from sqlobject import SQLObject, StringCol
|
|
2
|
+
from sqlobject.tests.dbtest import setupClass
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
########################################
|
|
6
|
+
# Expiring, syncing
|
|
7
|
+
########################################
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class SyncTest(SQLObject):
|
|
11
|
+
name = StringCol(length=50, alternateID=True, dbName='name_col')
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def test_expire():
|
|
15
|
+
setupClass(SyncTest)
|
|
16
|
+
SyncTest(name='bob')
|
|
17
|
+
SyncTest(name='tim')
|
|
18
|
+
|
|
19
|
+
conn = SyncTest._connection
|
|
20
|
+
b = SyncTest.byName('bob')
|
|
21
|
+
conn.query("UPDATE sync_test SET name_col = 'robert' WHERE id = %i"
|
|
22
|
+
% b.id)
|
|
23
|
+
assert b.name == 'bob'
|
|
24
|
+
b.expire()
|
|
25
|
+
assert b.name == 'robert'
|
|
26
|
+
conn.query("UPDATE sync_test SET name_col = 'bobby' WHERE id = %i"
|
|
27
|
+
% b.id)
|
|
28
|
+
b.sync()
|
|
29
|
+
assert b.name == 'bobby'
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
from sqlobject import IntCol, SQLObject, StringCol
|
|
2
|
+
from sqlobject.sqlbuilder import Select, func
|
|
3
|
+
from sqlobject.tests.dbtest import getConnection, setupClass
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
########################################
|
|
7
|
+
# groupBy
|
|
8
|
+
########################################
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class GroupbyTest(SQLObject):
|
|
12
|
+
name = StringCol()
|
|
13
|
+
so_value = IntCol()
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def test_groupBy():
|
|
17
|
+
setupClass(GroupbyTest)
|
|
18
|
+
GroupbyTest(name='a', so_value=1)
|
|
19
|
+
GroupbyTest(name='a', so_value=2)
|
|
20
|
+
GroupbyTest(name='b', so_value=1)
|
|
21
|
+
|
|
22
|
+
connection = getConnection()
|
|
23
|
+
select = Select(
|
|
24
|
+
[GroupbyTest.q.name, func.COUNT(GroupbyTest.q.so_value)],
|
|
25
|
+
groupBy=GroupbyTest.q.name,
|
|
26
|
+
orderBy=GroupbyTest.q.name)
|
|
27
|
+
sql = connection.sqlrepr(select)
|
|
28
|
+
rows = list(connection.queryAll(sql))
|
|
29
|
+
assert [tuple(t) for t in rows] == [('a', 2), ('b', 1)]
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def test_groupBy_list():
|
|
33
|
+
setupClass(GroupbyTest)
|
|
34
|
+
GroupbyTest(name='a', so_value=1)
|
|
35
|
+
GroupbyTest(name='a', so_value=2)
|
|
36
|
+
GroupbyTest(name='b', so_value=1)
|
|
37
|
+
|
|
38
|
+
connection = getConnection()
|
|
39
|
+
select = Select(
|
|
40
|
+
[GroupbyTest.q.name, GroupbyTest.q.so_value],
|
|
41
|
+
groupBy=[GroupbyTest.q.name, GroupbyTest.q.so_value],
|
|
42
|
+
orderBy=[GroupbyTest.q.name, GroupbyTest.q.so_value])
|
|
43
|
+
sql = connection.sqlrepr(select)
|
|
44
|
+
rows = list(connection.queryAll(sql))
|
|
45
|
+
assert [tuple(t) for t in rows] == [('a', 1), ('a', 2), ('b', 1)]
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
from sqlobject import IntCol, SQLObject
|
|
2
|
+
from sqlobject.tests.dbtest import getConnection, setupClass
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
########################################
|
|
6
|
+
# Identity (MS SQL)
|
|
7
|
+
########################################
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class SOTestIdentity(SQLObject):
|
|
11
|
+
n = IntCol()
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def test_identity():
|
|
15
|
+
# (re)create table
|
|
16
|
+
SOTestIdentity.dropTable(connection=getConnection(), ifExists=True)
|
|
17
|
+
setupClass(SOTestIdentity)
|
|
18
|
+
|
|
19
|
+
# insert without giving identity
|
|
20
|
+
SOTestIdentity(n=100) # i1
|
|
21
|
+
# verify result
|
|
22
|
+
i1get = SOTestIdentity.get(1)
|
|
23
|
+
assert (i1get.n == 100)
|
|
24
|
+
|
|
25
|
+
# insert while giving identity
|
|
26
|
+
SOTestIdentity(id=2, n=200) # i2
|
|
27
|
+
# verify result
|
|
28
|
+
i2get = SOTestIdentity.get(2)
|
|
29
|
+
assert (i2get.n == 200)
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
from sqlobject import DatabaseIndex, ForeignKey, IntCol, MultipleJoin, \
|
|
3
|
+
SQLObject, StringCol
|
|
4
|
+
from sqlobject.dberrors import DatabaseError, IntegrityError, \
|
|
5
|
+
OperationalError, ProgrammingError
|
|
6
|
+
from sqlobject.tests.dbtest import raises, setupClass, supports
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
########################################
|
|
10
|
+
# Indexes
|
|
11
|
+
########################################
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class SOIndex1(SQLObject):
|
|
15
|
+
name = StringCol(length=100)
|
|
16
|
+
number = IntCol()
|
|
17
|
+
|
|
18
|
+
nameIndex = DatabaseIndex('name', unique=True)
|
|
19
|
+
nameIndex2 = DatabaseIndex(name, number)
|
|
20
|
+
nameIndex3 = DatabaseIndex({'column': name,
|
|
21
|
+
'length': 3})
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class SOIndex2(SQLObject):
|
|
25
|
+
name = StringCol(length=100)
|
|
26
|
+
nameIndex = DatabaseIndex({'expression': 'lower(name)'})
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def test_indexes_1():
|
|
30
|
+
setupClass(SOIndex1)
|
|
31
|
+
n = 0
|
|
32
|
+
for name in 'blah blech boring yep yort snort'.split():
|
|
33
|
+
n += 1
|
|
34
|
+
SOIndex1(name=name, number=n)
|
|
35
|
+
mod = SOIndex1._connection.module
|
|
36
|
+
raises(
|
|
37
|
+
(mod.ProgrammingError, mod.IntegrityError,
|
|
38
|
+
mod.OperationalError, mod.DatabaseError,
|
|
39
|
+
ProgrammingError, IntegrityError, OperationalError, DatabaseError),
|
|
40
|
+
SOIndex1, name='blah', number=0)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def test_indexes_2():
|
|
44
|
+
if not supports('expressionIndex'):
|
|
45
|
+
pytest.skip("expressionIndex isn't supported")
|
|
46
|
+
setupClass(SOIndex2)
|
|
47
|
+
SOIndex2(name='')
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class PersonIndexGet(SQLObject):
|
|
51
|
+
firstName = StringCol(length=100)
|
|
52
|
+
lastName = StringCol(length=100)
|
|
53
|
+
age = IntCol(alternateID=True)
|
|
54
|
+
nameIndex = DatabaseIndex(firstName, lastName, unique=True)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def test_index_get_1():
|
|
58
|
+
setupClass(PersonIndexGet, force=True)
|
|
59
|
+
|
|
60
|
+
PersonIndexGet(firstName='Eric', lastName='Idle', age=62)
|
|
61
|
+
PersonIndexGet(firstName='Terry', lastName='Gilliam', age=65)
|
|
62
|
+
PersonIndexGet(firstName='John', lastName='Cleese', age=66)
|
|
63
|
+
|
|
64
|
+
PersonIndexGet.get(1)
|
|
65
|
+
PersonIndexGet.nameIndex.get('Terry', 'Gilliam')
|
|
66
|
+
PersonIndexGet.nameIndex.get(firstName='John', lastName='Cleese')
|
|
67
|
+
|
|
68
|
+
raises(Exception, PersonIndexGet.nameIndex.get,
|
|
69
|
+
firstName='Graham', lastName='Chapman')
|
|
70
|
+
|
|
71
|
+
raises(Exception, PersonIndexGet.nameIndex.get,
|
|
72
|
+
'Terry', lastName='Gilliam')
|
|
73
|
+
|
|
74
|
+
raises(Exception, PersonIndexGet.nameIndex.get, 'Terry', 'Gilliam', 65)
|
|
75
|
+
|
|
76
|
+
raises(Exception, PersonIndexGet.nameIndex.get, 'Terry')
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
class PersonIndexGet2(SQLObject):
|
|
80
|
+
name = StringCol(alternateID=True, length=100)
|
|
81
|
+
age = IntCol()
|
|
82
|
+
addresses = MultipleJoin('AddressIndexGet2')
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
class AddressIndexGet2(SQLObject):
|
|
86
|
+
person = ForeignKey('PersonIndexGet2', notNone=True)
|
|
87
|
+
type = StringCol(notNone=True, length=100)
|
|
88
|
+
street = StringCol(notNone=True)
|
|
89
|
+
pk = DatabaseIndex(person, type, unique=True)
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def test_index_get_2():
|
|
93
|
+
setupClass([PersonIndexGet2, AddressIndexGet2])
|
|
94
|
+
|
|
95
|
+
p = PersonIndexGet2(name='Terry Guilliam', age=64)
|
|
96
|
+
AddressIndexGet2(person=p, type='home', street='Terry Street 234')
|
|
97
|
+
AddressIndexGet2(person=p, type='work', street='Guilliam Street 234')
|
|
98
|
+
|
|
99
|
+
AddressIndexGet2.pk.get(p, 'work')
|
|
100
|
+
AddressIndexGet2.pk.get(person=p, type='work')
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
from sqlobject import SQLObject, StringCol
|
|
2
|
+
from sqlobject.tests.dbtest import setupClass
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
########################################
|
|
6
|
+
# Inheritance
|
|
7
|
+
########################################
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class Super(SQLObject):
|
|
11
|
+
|
|
12
|
+
name = StringCol(length=10)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class Sub(Super):
|
|
16
|
+
|
|
17
|
+
name2 = StringCol(length=10)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def test_super():
|
|
21
|
+
setupClass(Super)
|
|
22
|
+
setupClass(Sub)
|
|
23
|
+
s1 = Super(name='one')
|
|
24
|
+
Super(name='two') # s2
|
|
25
|
+
s3 = Super.get(s1.id)
|
|
26
|
+
assert s1 == s3
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def test_sub():
|
|
30
|
+
setupClass(Super)
|
|
31
|
+
setupClass(Sub)
|
|
32
|
+
s1 = Sub(name='one', name2='1')
|
|
33
|
+
Sub(name='two', name2='2') # s2
|
|
34
|
+
s3 = Sub.get(s1.id)
|
|
35
|
+
assert s1 == s3
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
from sqlobject import ForeignKey, MultipleJoin, RelatedJoin, SQLObject, \
|
|
2
|
+
StringCol
|
|
3
|
+
from sqlobject.tests.dbtest import setupClass
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
########################################
|
|
7
|
+
# Joins
|
|
8
|
+
########################################
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class PersonJoiner(SQLObject):
|
|
12
|
+
|
|
13
|
+
name = StringCol(length=40, alternateID=True)
|
|
14
|
+
addressJoiners = RelatedJoin('AddressJoiner')
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class AddressJoiner(SQLObject):
|
|
18
|
+
|
|
19
|
+
zip = StringCol(length=5, alternateID=True)
|
|
20
|
+
personJoiners = RelatedJoin('PersonJoiner')
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class ImplicitJoiningSO(SQLObject):
|
|
24
|
+
foo = RelatedJoin('Bar')
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class ExplicitJoiningSO(SQLObject):
|
|
28
|
+
foo = MultipleJoin('Bar', joinMethodName='foo')
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class TestJoin:
|
|
32
|
+
|
|
33
|
+
def setup_method(self, meth):
|
|
34
|
+
setupClass(PersonJoiner)
|
|
35
|
+
setupClass(AddressJoiner)
|
|
36
|
+
for n in ['bob', 'tim', 'jane', 'joe', 'fred', 'barb']:
|
|
37
|
+
PersonJoiner(name=n)
|
|
38
|
+
for z in ['11111', '22222', '33333', '44444']:
|
|
39
|
+
AddressJoiner(zip=z)
|
|
40
|
+
|
|
41
|
+
def test_join(self):
|
|
42
|
+
b = PersonJoiner.byName('bob')
|
|
43
|
+
assert b.addressJoiners == []
|
|
44
|
+
z = AddressJoiner.byZip('11111')
|
|
45
|
+
b.addAddressJoiner(z)
|
|
46
|
+
self.assertZipsEqual(b.addressJoiners, ['11111'])
|
|
47
|
+
self.assertNamesEqual(z.personJoiners, ['bob'])
|
|
48
|
+
z2 = AddressJoiner.byZip('22222')
|
|
49
|
+
b.addAddressJoiner(z2)
|
|
50
|
+
self.assertZipsEqual(b.addressJoiners, ['11111', '22222'])
|
|
51
|
+
self.assertNamesEqual(z2.personJoiners, ['bob'])
|
|
52
|
+
b.removeAddressJoiner(z)
|
|
53
|
+
self.assertZipsEqual(b.addressJoiners, ['22222'])
|
|
54
|
+
self.assertNamesEqual(z.personJoiners, [])
|
|
55
|
+
|
|
56
|
+
def assertZipsEqual(self, zips, dest):
|
|
57
|
+
assert [a.zip for a in zips] == dest
|
|
58
|
+
|
|
59
|
+
def assertNamesEqual(self, people, dest):
|
|
60
|
+
assert [p.name for p in people] == dest
|
|
61
|
+
|
|
62
|
+
def test_joinAttributeWithUnderscores(self):
|
|
63
|
+
# Make sure that the implicit setting of joinMethodName works
|
|
64
|
+
assert hasattr(ImplicitJoiningSO, 'foo')
|
|
65
|
+
assert not hasattr(ImplicitJoiningSO, 'bars')
|
|
66
|
+
|
|
67
|
+
# And make sure explicit setting also works
|
|
68
|
+
assert hasattr(ExplicitJoiningSO, 'foo')
|
|
69
|
+
assert not hasattr(ExplicitJoiningSO, 'bars')
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
class PersonJoiner2(SQLObject):
|
|
73
|
+
|
|
74
|
+
name = StringCol('name', length=40, alternateID=True)
|
|
75
|
+
addressJoiner2s = MultipleJoin('AddressJoiner2')
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
class AddressJoiner2(SQLObject):
|
|
79
|
+
|
|
80
|
+
class sqlmeta:
|
|
81
|
+
defaultOrder = ['-zip', 'plus4']
|
|
82
|
+
|
|
83
|
+
zip = StringCol(length=5)
|
|
84
|
+
plus4 = StringCol(length=4, default=None)
|
|
85
|
+
personJoiner2 = ForeignKey('PersonJoiner2')
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
class TestJoin2:
|
|
89
|
+
|
|
90
|
+
def setup_method(self, meth):
|
|
91
|
+
setupClass([PersonJoiner2, AddressJoiner2])
|
|
92
|
+
p1 = PersonJoiner2(name='bob')
|
|
93
|
+
p2 = PersonJoiner2(name='sally')
|
|
94
|
+
for z in ['11111', '22222', '33333']:
|
|
95
|
+
AddressJoiner2(zip=z, personJoiner2=p1)
|
|
96
|
+
AddressJoiner2(zip='00000', personJoiner2=p2)
|
|
97
|
+
|
|
98
|
+
def test_basic(self):
|
|
99
|
+
bob = PersonJoiner2.byName('bob')
|
|
100
|
+
sally = PersonJoiner2.byName('sally')
|
|
101
|
+
assert len(bob.addressJoiner2s) == 3
|
|
102
|
+
assert len(sally.addressJoiner2s) == 1
|
|
103
|
+
bob.addressJoiner2s[0].destroySelf()
|
|
104
|
+
assert len(bob.addressJoiner2s) == 2
|
|
105
|
+
z = bob.addressJoiner2s[0]
|
|
106
|
+
z.zip = 'xxxxx'
|
|
107
|
+
id = z.id
|
|
108
|
+
del z
|
|
109
|
+
z = AddressJoiner2.get(id)
|
|
110
|
+
assert z.zip == 'xxxxx'
|
|
111
|
+
|
|
112
|
+
def test_defaultOrder(self):
|
|
113
|
+
p1 = PersonJoiner2.byName('bob')
|
|
114
|
+
assert ([i.zip for i in p1.addressJoiner2s]
|
|
115
|
+
== ['33333', '22222', '11111'])
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
_personJoiner3_getters = []
|
|
119
|
+
_personJoiner3_setters = []
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
class PersonJoiner3(SQLObject):
|
|
123
|
+
|
|
124
|
+
name = StringCol('name', length=40, alternateID=True)
|
|
125
|
+
addressJoiner3s = MultipleJoin('AddressJoiner3')
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
class AddressJoiner3(SQLObject):
|
|
129
|
+
|
|
130
|
+
zip = StringCol(length=5)
|
|
131
|
+
personJoiner3 = ForeignKey('PersonJoiner3')
|
|
132
|
+
|
|
133
|
+
def _get_personJoiner3(self):
|
|
134
|
+
value = self._SO_get_personJoiner3()
|
|
135
|
+
_personJoiner3_getters.append((self, value))
|
|
136
|
+
return value
|
|
137
|
+
|
|
138
|
+
def _set_personJoiner3(self, value):
|
|
139
|
+
self._SO_set_personJoiner3(value)
|
|
140
|
+
_personJoiner3_setters.append((self, value))
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
class TestJoin3:
|
|
144
|
+
|
|
145
|
+
def setup_method(self, meth):
|
|
146
|
+
setupClass([PersonJoiner3, AddressJoiner3])
|
|
147
|
+
p1 = PersonJoiner3(name='bob')
|
|
148
|
+
p2 = PersonJoiner3(name='sally')
|
|
149
|
+
for z in ['11111', '22222', '33333']:
|
|
150
|
+
AddressJoiner3(zip=z, personJoiner3=p1)
|
|
151
|
+
AddressJoiner3(zip='00000', personJoiner3=p2)
|
|
152
|
+
|
|
153
|
+
def test_accessors(self):
|
|
154
|
+
assert len(_personJoiner3_getters) == 0
|
|
155
|
+
assert len(_personJoiner3_setters) == 4
|
|
156
|
+
bob = PersonJoiner3.byName('bob')
|
|
157
|
+
for addressJoiner3 in bob.addressJoiner3s:
|
|
158
|
+
addressJoiner3.personJoiner3
|
|
159
|
+
assert len(_personJoiner3_getters) == 3
|
|
160
|
+
assert len(_personJoiner3_setters) == 4
|