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,143 @@
|
|
|
1
|
+
from sqlobject import SQLObject, StringCol
|
|
2
|
+
from sqlobject.sqlbuilder import JOIN, LEFTJOIN, LEFTJOINConditional, \
|
|
3
|
+
LEFTJOINOn, LEFTJOINUsing
|
|
4
|
+
from sqlobject.tests.dbtest import getConnection, setupClass
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
########################################
|
|
8
|
+
# Condiotional joins
|
|
9
|
+
########################################
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class SOTestJoin1(SQLObject):
|
|
13
|
+
col1 = StringCol()
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class SOTestJoin2(SQLObject):
|
|
17
|
+
col2 = StringCol()
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class SOTestJoin3(SQLObject):
|
|
21
|
+
col3 = StringCol()
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class SOTestJoin4(SQLObject):
|
|
25
|
+
col4 = StringCol()
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class SOTestJoin5(SQLObject):
|
|
29
|
+
col5 = StringCol()
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def setup():
|
|
33
|
+
setupClass(SOTestJoin1)
|
|
34
|
+
setupClass(SOTestJoin2)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def test_1syntax():
|
|
38
|
+
setup()
|
|
39
|
+
join = JOIN("table1", "table2")
|
|
40
|
+
assert str(join) == "table1 JOIN table2"
|
|
41
|
+
join = LEFTJOIN("table1", "table2")
|
|
42
|
+
assert str(join) == "table1 LEFT JOIN table2"
|
|
43
|
+
join = LEFTJOINOn("table1", "table2", "tabl1.col1 = table2.col2")
|
|
44
|
+
assert getConnection().sqlrepr(join) == \
|
|
45
|
+
"table1 LEFT JOIN table2 ON tabl1.col1 = table2.col2"
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def test_2select_syntax():
|
|
49
|
+
setup()
|
|
50
|
+
select = SOTestJoin1.select(
|
|
51
|
+
join=LEFTJOINConditional(SOTestJoin1, SOTestJoin2,
|
|
52
|
+
on_condition=(
|
|
53
|
+
SOTestJoin1.q.col1 == SOTestJoin2.q.col2))
|
|
54
|
+
)
|
|
55
|
+
assert str(select) == \
|
|
56
|
+
"SELECT so_test_join1.id, so_test_join1.col1 " \
|
|
57
|
+
"FROM so_test_join1 " \
|
|
58
|
+
"LEFT JOIN so_test_join2 " \
|
|
59
|
+
"ON ((so_test_join1.col1) = (so_test_join2.col2)) WHERE 1 = 1"
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def test_3perform_join():
|
|
63
|
+
setup()
|
|
64
|
+
SOTestJoin1(col1="test1")
|
|
65
|
+
SOTestJoin1(col1="test2")
|
|
66
|
+
SOTestJoin1(col1="test3")
|
|
67
|
+
SOTestJoin2(col2="test1")
|
|
68
|
+
SOTestJoin2(col2="test2")
|
|
69
|
+
|
|
70
|
+
select = SOTestJoin1.select(
|
|
71
|
+
join=LEFTJOINOn(SOTestJoin1, SOTestJoin2,
|
|
72
|
+
SOTestJoin1.q.col1 == SOTestJoin2.q.col2)
|
|
73
|
+
)
|
|
74
|
+
assert select.count() == 3
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def test_4join_3tables_syntax():
|
|
78
|
+
setup()
|
|
79
|
+
setupClass(SOTestJoin3)
|
|
80
|
+
|
|
81
|
+
select = SOTestJoin1.select(
|
|
82
|
+
join=LEFTJOIN(SOTestJoin2, SOTestJoin3)
|
|
83
|
+
)
|
|
84
|
+
assert str(select) == \
|
|
85
|
+
"SELECT so_test_join1.id, so_test_join1.col1 " \
|
|
86
|
+
"FROM so_test_join1, so_test_join2 LEFT JOIN so_test_join3 WHERE 1 = 1"
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def test_5join_3tables_syntax2():
|
|
90
|
+
setup()
|
|
91
|
+
setupClass(SOTestJoin3)
|
|
92
|
+
|
|
93
|
+
select = SOTestJoin1.select(
|
|
94
|
+
join=(LEFTJOIN(None, SOTestJoin2), LEFTJOIN(None, SOTestJoin3))
|
|
95
|
+
)
|
|
96
|
+
assert str(select) == \
|
|
97
|
+
"SELECT so_test_join1.id, so_test_join1.col1 " \
|
|
98
|
+
"FROM so_test_join1 " \
|
|
99
|
+
"LEFT JOIN so_test_join2 LEFT JOIN so_test_join3 WHERE 1 = 1"
|
|
100
|
+
|
|
101
|
+
select = SOTestJoin1.select(
|
|
102
|
+
join=(LEFTJOIN(SOTestJoin1, SOTestJoin2),
|
|
103
|
+
LEFTJOIN(SOTestJoin1, SOTestJoin3))
|
|
104
|
+
)
|
|
105
|
+
assert str(select) == \
|
|
106
|
+
"SELECT so_test_join1.id, so_test_join1.col1 " \
|
|
107
|
+
"FROM so_test_join1 " \
|
|
108
|
+
"LEFT JOIN so_test_join2, so_test_join1 " \
|
|
109
|
+
"LEFT JOIN so_test_join3 WHERE 1 = 1"
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def test_6join_using():
|
|
113
|
+
setup()
|
|
114
|
+
setupClass(SOTestJoin3)
|
|
115
|
+
|
|
116
|
+
select = SOTestJoin1.select(
|
|
117
|
+
join=LEFTJOINUsing(None, SOTestJoin2, [SOTestJoin2.q.id])
|
|
118
|
+
)
|
|
119
|
+
assert str(select) == \
|
|
120
|
+
"SELECT so_test_join1.id, so_test_join1.col1 " \
|
|
121
|
+
"FROM so_test_join1 " \
|
|
122
|
+
"LEFT JOIN so_test_join2 USING (so_test_join2.id) WHERE 1 = 1"
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def test_7join_on():
|
|
126
|
+
setup()
|
|
127
|
+
setupClass(SOTestJoin3)
|
|
128
|
+
setupClass(SOTestJoin4)
|
|
129
|
+
setupClass(SOTestJoin5)
|
|
130
|
+
|
|
131
|
+
select = SOTestJoin1.select(join=(
|
|
132
|
+
LEFTJOINOn(SOTestJoin2, SOTestJoin3,
|
|
133
|
+
SOTestJoin2.q.col2 == SOTestJoin3.q.col3),
|
|
134
|
+
LEFTJOINOn(SOTestJoin4, SOTestJoin5,
|
|
135
|
+
SOTestJoin4.q.col4 == SOTestJoin5.q.col5)
|
|
136
|
+
))
|
|
137
|
+
assert str(select) == \
|
|
138
|
+
"SELECT so_test_join1.id, so_test_join1.col1 " \
|
|
139
|
+
"FROM so_test_join1, so_test_join2 " \
|
|
140
|
+
"LEFT JOIN so_test_join3 " \
|
|
141
|
+
"ON ((so_test_join2.col2) = (so_test_join3.col3)), so_test_join4 " \
|
|
142
|
+
"LEFT JOIN so_test_join5 " \
|
|
143
|
+
"ON ((so_test_join4.col4) = (so_test_join5.col5)) WHERE 1 = 1"
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
from sqlobject import SQLObject, JsonbCol
|
|
3
|
+
from sqlobject.tests.dbtest import getConnection, setupClass
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
########################################
|
|
7
|
+
# Jsonb columns
|
|
8
|
+
########################################
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class JsonbContainer(SQLObject):
|
|
12
|
+
jsondata = JsonbCol(default=None)
|
|
13
|
+
jsondata_none = JsonbCol(default=None)
|
|
14
|
+
jsondata_list = JsonbCol(default=None)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
dictdata = dict(
|
|
18
|
+
ship=u'USS Voyager',
|
|
19
|
+
number='NCC-74656',
|
|
20
|
+
crew=['Cpt. Janeway', 'Doctor', 'Lt. Torries', 'Seven of Nine'],
|
|
21
|
+
races=('Borg', 'Kason',),
|
|
22
|
+
distance2earth=70000,
|
|
23
|
+
coming_home=True)
|
|
24
|
+
|
|
25
|
+
nonedata = None
|
|
26
|
+
|
|
27
|
+
listofdictsdata = [dict(Erath=7390000000),
|
|
28
|
+
dict(Vulcan=6000000000),
|
|
29
|
+
dict(Kronos='unknown')]
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def test_jsonbCol():
|
|
33
|
+
connection = getConnection()
|
|
34
|
+
if connection.dbName != "postgres":
|
|
35
|
+
pytest.skip("These tests require PostgreSQL")
|
|
36
|
+
|
|
37
|
+
setupClass([JsonbContainer], force=True)
|
|
38
|
+
|
|
39
|
+
my_jsonb = JsonbContainer(
|
|
40
|
+
jsondata=dictdata,
|
|
41
|
+
jsondata_none=nonedata,
|
|
42
|
+
jsondata_list=listofdictsdata)
|
|
43
|
+
iid = my_jsonb.id
|
|
44
|
+
|
|
45
|
+
JsonbContainer._connection.cache.clear()
|
|
46
|
+
|
|
47
|
+
my_jsonb_2 = JsonbContainer.get(iid)
|
|
48
|
+
|
|
49
|
+
assert my_jsonb_2.jsondata['coming_home'] == dictdata['coming_home']
|
|
50
|
+
assert my_jsonb_2.jsondata['crew'] == dictdata['crew']
|
|
51
|
+
assert my_jsonb_2.jsondata['races'] == ['Borg', 'Kason']
|
|
52
|
+
assert my_jsonb_2.jsondata_none is None
|
|
53
|
+
assert my_jsonb_2.jsondata_list == listofdictsdata
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
from sqlobject import SQLObject, JSONCol
|
|
3
|
+
from sqlobject.tests.dbtest import setupClass
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class JSONTest(SQLObject):
|
|
7
|
+
json = JSONCol(default=None)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
_json_test_data = (
|
|
11
|
+
None, True, 1, 2.0,
|
|
12
|
+
{u"test": [None, True, 1, 2.0,
|
|
13
|
+
{u"unicode'with'apostrophes": u"unicode\"with\"quotes"},
|
|
14
|
+
[],
|
|
15
|
+
u"unicode"]},
|
|
16
|
+
[None, True, 1, 2.0,
|
|
17
|
+
[],
|
|
18
|
+
{u"unicode'with'apostrophes": u"unicode\"with\"quotes"},
|
|
19
|
+
u"unicode", u"unicode'with'apostrophes", u"unicode\"with\"quotes",
|
|
20
|
+
],
|
|
21
|
+
u"unicode", u"unicode'with'apostrophes", u"unicode\"with\"quotes",
|
|
22
|
+
{'test': 'Test'},
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def _setup():
|
|
27
|
+
setupClass(JSONTest)
|
|
28
|
+
|
|
29
|
+
for _id, test_data in enumerate(_json_test_data):
|
|
30
|
+
JSONTest(id=_id + 1, json=test_data)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def test_JSONCol():
|
|
34
|
+
_setup()
|
|
35
|
+
JSONTest._connection.cache.clear()
|
|
36
|
+
|
|
37
|
+
for _id, test_data in enumerate(_json_test_data):
|
|
38
|
+
json = JSONTest.get(_id + 1)
|
|
39
|
+
assert json.json == test_data
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def test_JSONCol_funcs():
|
|
43
|
+
connection = JSONTest._connection
|
|
44
|
+
if not hasattr(connection, 'can_use_json_funcs') \
|
|
45
|
+
or not connection.can_use_json_funcs():
|
|
46
|
+
pytest.skip(
|
|
47
|
+
"The database doesn't support JSON functions; "
|
|
48
|
+
"JSON functions are supported by MariaDB since version 10.2.7 "
|
|
49
|
+
"and by MySQL since version 5.7.")
|
|
50
|
+
_setup()
|
|
51
|
+
|
|
52
|
+
rows = list(
|
|
53
|
+
JSONTest.select(JSONTest.q.json.json_extract('test') == 'Test')
|
|
54
|
+
)
|
|
55
|
+
assert len(rows) == 1
|
|
56
|
+
assert rows[0].json == {'test': 'Test'}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
from sqlobject import SQLObject, StringCol
|
|
2
|
+
from sqlobject.tests.dbtest import setupClass
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
########################################
|
|
6
|
+
# Lazy updates
|
|
7
|
+
########################################
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class Lazy(SQLObject):
|
|
11
|
+
|
|
12
|
+
class sqlmeta:
|
|
13
|
+
lazyUpdate = True
|
|
14
|
+
name = StringCol()
|
|
15
|
+
other = StringCol(default='nothing')
|
|
16
|
+
third = StringCol(default='third')
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class TestLazyTest:
|
|
20
|
+
|
|
21
|
+
def setup_method(self, meth):
|
|
22
|
+
# All this stuff is so that we can track when the connection
|
|
23
|
+
# does an actual update; we put in a new _SO_update method
|
|
24
|
+
# that calls the original and sets an instance variable that
|
|
25
|
+
# we can later check.
|
|
26
|
+
setupClass(Lazy)
|
|
27
|
+
self.conn = Lazy._connection
|
|
28
|
+
self.conn.didUpdate = False
|
|
29
|
+
self._oldUpdate = self.conn._SO_update
|
|
30
|
+
newUpdate = (
|
|
31
|
+
lambda so, values, s=self, c=self.conn, o=self._oldUpdate:
|
|
32
|
+
self._alternateUpdate(so, values, c, o))
|
|
33
|
+
self.conn._SO_update = newUpdate
|
|
34
|
+
|
|
35
|
+
def teardown_method(self, meth):
|
|
36
|
+
self.conn._SO_update = self._oldUpdate
|
|
37
|
+
del self._oldUpdate
|
|
38
|
+
|
|
39
|
+
def _alternateUpdate(self, so, values, conn, oldUpdate):
|
|
40
|
+
conn.didUpdate = True
|
|
41
|
+
return oldUpdate(so, values)
|
|
42
|
+
|
|
43
|
+
def test_lazy(self):
|
|
44
|
+
assert not self.conn.didUpdate
|
|
45
|
+
obj = Lazy(name='tim')
|
|
46
|
+
# We just did an insert, but not an update:
|
|
47
|
+
assert not self.conn.didUpdate
|
|
48
|
+
obj.set(name='joe')
|
|
49
|
+
assert obj.sqlmeta.dirty
|
|
50
|
+
assert obj.name == 'joe'
|
|
51
|
+
assert not self.conn.didUpdate
|
|
52
|
+
obj.syncUpdate()
|
|
53
|
+
assert obj.name == 'joe'
|
|
54
|
+
assert self.conn.didUpdate
|
|
55
|
+
assert not obj.sqlmeta.dirty
|
|
56
|
+
assert obj.name == 'joe'
|
|
57
|
+
self.conn.didUpdate = False
|
|
58
|
+
|
|
59
|
+
obj = Lazy(name='frank')
|
|
60
|
+
obj.name = 'joe'
|
|
61
|
+
assert not self.conn.didUpdate
|
|
62
|
+
assert obj.sqlmeta.dirty
|
|
63
|
+
assert obj.name == 'joe'
|
|
64
|
+
obj.name = 'joe2'
|
|
65
|
+
assert not self.conn.didUpdate
|
|
66
|
+
assert obj.sqlmeta.dirty
|
|
67
|
+
assert obj.name == 'joe2'
|
|
68
|
+
obj.syncUpdate()
|
|
69
|
+
assert obj.name == 'joe2'
|
|
70
|
+
assert not obj.sqlmeta.dirty
|
|
71
|
+
assert self.conn.didUpdate
|
|
72
|
+
self.conn.didUpdate = False
|
|
73
|
+
|
|
74
|
+
obj = Lazy(name='loaded')
|
|
75
|
+
assert not obj.sqlmeta.dirty
|
|
76
|
+
assert not self.conn.didUpdate
|
|
77
|
+
assert obj.name == 'loaded'
|
|
78
|
+
obj.name = 'unloaded'
|
|
79
|
+
assert obj.sqlmeta.dirty
|
|
80
|
+
assert obj.name == 'unloaded'
|
|
81
|
+
assert not self.conn.didUpdate
|
|
82
|
+
obj.sync()
|
|
83
|
+
assert not obj.sqlmeta.dirty
|
|
84
|
+
assert obj.name == 'unloaded'
|
|
85
|
+
assert self.conn.didUpdate
|
|
86
|
+
self.conn.didUpdate = False
|
|
87
|
+
obj.name = 'whatever'
|
|
88
|
+
assert obj.sqlmeta.dirty
|
|
89
|
+
assert obj.name == 'whatever'
|
|
90
|
+
assert not self.conn.didUpdate
|
|
91
|
+
obj._SO_loadValue('name')
|
|
92
|
+
assert obj.sqlmeta.dirty
|
|
93
|
+
assert obj.name == 'whatever'
|
|
94
|
+
assert not self.conn.didUpdate
|
|
95
|
+
obj._SO_loadValue('other')
|
|
96
|
+
assert obj.name == 'whatever'
|
|
97
|
+
assert not self.conn.didUpdate
|
|
98
|
+
obj.syncUpdate()
|
|
99
|
+
assert self.conn.didUpdate
|
|
100
|
+
self.conn.didUpdate = False
|
|
101
|
+
|
|
102
|
+
# Now, check that get() doesn't screw
|
|
103
|
+
# cached objects' validator state.
|
|
104
|
+
obj_id = obj.id
|
|
105
|
+
old_state = obj._SO_validatorState
|
|
106
|
+
obj = Lazy.get(obj_id)
|
|
107
|
+
assert not obj.sqlmeta.dirty
|
|
108
|
+
assert not self.conn.didUpdate
|
|
109
|
+
assert obj._SO_validatorState is old_state
|
|
110
|
+
assert obj.name == 'whatever'
|
|
111
|
+
obj.name = 'unloaded'
|
|
112
|
+
assert obj.name == 'unloaded'
|
|
113
|
+
assert obj.sqlmeta.dirty
|
|
114
|
+
assert not self.conn.didUpdate
|
|
115
|
+
# Fetch the object again with get() and
|
|
116
|
+
# make sure sqlmeta.dirty is still set, as the
|
|
117
|
+
# object should come from the cache.
|
|
118
|
+
obj = Lazy.get(obj_id)
|
|
119
|
+
assert obj.sqlmeta.dirty
|
|
120
|
+
assert not self.conn.didUpdate
|
|
121
|
+
assert obj.name == 'unloaded'
|
|
122
|
+
obj.syncUpdate()
|
|
123
|
+
assert self.conn.didUpdate
|
|
124
|
+
assert not obj.sqlmeta.dirty
|
|
125
|
+
self.conn.didUpdate = False
|
|
126
|
+
|
|
127
|
+
# Then clear the cache, and try a get()
|
|
128
|
+
# again, to make sure stuf like _SO_createdValues
|
|
129
|
+
# is properly initialized.
|
|
130
|
+
self.conn.cache.clear()
|
|
131
|
+
obj = Lazy.get(obj_id)
|
|
132
|
+
assert not obj.sqlmeta.dirty
|
|
133
|
+
assert not self.conn.didUpdate
|
|
134
|
+
assert obj.name == 'unloaded'
|
|
135
|
+
obj.name = 'spongebob'
|
|
136
|
+
assert obj.name == 'spongebob'
|
|
137
|
+
assert obj.sqlmeta.dirty
|
|
138
|
+
assert not self.conn.didUpdate
|
|
139
|
+
obj.syncUpdate()
|
|
140
|
+
assert self.conn.didUpdate
|
|
141
|
+
assert not obj.sqlmeta.dirty
|
|
142
|
+
self.conn.didUpdate = False
|
|
143
|
+
|
|
144
|
+
obj = Lazy(name='last')
|
|
145
|
+
assert not obj.sqlmeta.dirty
|
|
146
|
+
obj.syncUpdate()
|
|
147
|
+
assert not self.conn.didUpdate
|
|
148
|
+
assert not obj.sqlmeta.dirty
|
|
149
|
+
# Check that setting multiple values
|
|
150
|
+
# actually works. This was broken
|
|
151
|
+
# and just worked because we were testing
|
|
152
|
+
# only one value at a time, so 'name'
|
|
153
|
+
# had the right value after the for loop *wink*
|
|
154
|
+
# Also, check that passing a name that is not
|
|
155
|
+
# a valid column doesn't break, but instead
|
|
156
|
+
# just does a plain setattr.
|
|
157
|
+
obj.set(name='first', other='who', third='yes')
|
|
158
|
+
assert obj.name == 'first'
|
|
159
|
+
assert obj.other == 'who'
|
|
160
|
+
assert obj.third == 'yes'
|
|
161
|
+
assert obj.sqlmeta.dirty
|
|
162
|
+
assert not self.conn.didUpdate
|
|
163
|
+
obj.syncUpdate()
|
|
164
|
+
assert self.conn.didUpdate
|
|
165
|
+
assert not obj.sqlmeta.dirty
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
from hashlib import md5
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
########################################
|
|
5
|
+
# hashlib.md5
|
|
6
|
+
########################################
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def test_md5():
|
|
10
|
+
assert md5(b'').hexdigest() == 'd41d8cd98f00b204e9800998ecf8427e'
|
|
11
|
+
assert md5(b'\n').hexdigest() == '68b329da9893e34099c7d8ad5cb9c940'
|
|
12
|
+
assert md5(b'123').hexdigest() == '202cb962ac59075b964b07152d234b70'
|
|
13
|
+
assert md5(b'123\n').hexdigest() == 'ba1f2511fc30423bdbb183fe33f3dd0f'
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
from sqlobject import SQLObject, IntCol
|
|
3
|
+
from sqlobject.sqlbuilder import Select, ANY
|
|
4
|
+
from sqlobject.tests.dbtest import getConnection, setupClass
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
try:
|
|
8
|
+
connection = getConnection()
|
|
9
|
+
except (AttributeError, NameError):
|
|
10
|
+
# The module was imported during documentation building
|
|
11
|
+
pass
|
|
12
|
+
else:
|
|
13
|
+
if connection.dbName != "mysql":
|
|
14
|
+
pytestmark = pytest.mark.skip("These tests require MySQL")
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class SOTestSOListMySQL(SQLObject):
|
|
18
|
+
pass
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def test_list_databases():
|
|
22
|
+
assert connection.db in connection.listDatabases()
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def test_list_tables():
|
|
26
|
+
setupClass(SOTestSOListMySQL)
|
|
27
|
+
assert SOTestSOListMySQL.sqlmeta.table in connection.listTables()
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class SOTestANY(SQLObject):
|
|
31
|
+
value = IntCol()
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def test_ANY():
|
|
35
|
+
setupClass(SOTestANY)
|
|
36
|
+
SOTestANY(value=10)
|
|
37
|
+
SOTestANY(value=20)
|
|
38
|
+
SOTestANY(value=30)
|
|
39
|
+
assert len(list(SOTestANY.select(
|
|
40
|
+
SOTestANY.q.value > ANY(Select([SOTestANY.q.value]))))) == 2
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class SOTestMySQLidSize(SQLObject):
|
|
44
|
+
class sqlmeta:
|
|
45
|
+
idSize = 'BIG'
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def test_idSize():
|
|
49
|
+
assert 'id BIGINT PRIMARY KEY AUTO_INCREMENT' \
|
|
50
|
+
in SOTestMySQLidSize.createTableSQL(connection=connection)[0]
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
from __future__ import print_function
|
|
2
|
+
|
|
3
|
+
from sqlobject import ForeignKey, ManyToMany, OneToMany, SQLObject, StringCol
|
|
4
|
+
from sqlobject.tests.dbtest import setupClass
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
########################################
|
|
8
|
+
# Joins
|
|
9
|
+
########################################
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class PersonJNew(SQLObject):
|
|
13
|
+
|
|
14
|
+
name = StringCol(length=40, alternateID=True)
|
|
15
|
+
addressJs = ManyToMany('AddressJNew')
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class AddressJNew(SQLObject):
|
|
19
|
+
|
|
20
|
+
zip = StringCol(length=5, alternateID=True)
|
|
21
|
+
personJs = ManyToMany('PersonJNew')
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class ImplicitJoiningSONew(SQLObject):
|
|
25
|
+
foo = ManyToMany('Bar')
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class ExplicitJoiningSONew(SQLObject):
|
|
29
|
+
foo = OneToMany('Bar')
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class TestJoin:
|
|
33
|
+
|
|
34
|
+
def setup_method(self, meth):
|
|
35
|
+
setupClass(PersonJNew)
|
|
36
|
+
setupClass(AddressJNew)
|
|
37
|
+
for n in ['bob', 'tim', 'jane', 'joe', 'fred', 'barb']:
|
|
38
|
+
PersonJNew(name=n)
|
|
39
|
+
for z in ['11111', '22222', '33333', '44444']:
|
|
40
|
+
AddressJNew(zip=z)
|
|
41
|
+
|
|
42
|
+
def test_join(self):
|
|
43
|
+
b = PersonJNew.byName('bob')
|
|
44
|
+
assert list(b.addressJs) == []
|
|
45
|
+
z = AddressJNew.byZip('11111')
|
|
46
|
+
b.addressJs.add(z)
|
|
47
|
+
self.assertZipsEqual(b.addressJs, ['11111'])
|
|
48
|
+
print(str(z.personJs), repr(z.personJs))
|
|
49
|
+
self.assertNamesEqual(z.personJs, ['bob'])
|
|
50
|
+
z2 = AddressJNew.byZip('22222')
|
|
51
|
+
b.addressJs.add(z2)
|
|
52
|
+
print(str(b.addressJs))
|
|
53
|
+
self.assertZipsEqual(b.addressJs, ['11111', '22222'])
|
|
54
|
+
self.assertNamesEqual(z2.personJs, ['bob'])
|
|
55
|
+
b.addressJs.remove(z)
|
|
56
|
+
self.assertZipsEqual(b.addressJs, ['22222'])
|
|
57
|
+
self.assertNamesEqual(z.personJs, [])
|
|
58
|
+
|
|
59
|
+
def assertZipsEqual(self, zips, dest):
|
|
60
|
+
assert [a.zip for a in zips] == dest
|
|
61
|
+
|
|
62
|
+
def assertNamesEqual(self, people, dest):
|
|
63
|
+
assert [p.name for p in people] == dest
|
|
64
|
+
|
|
65
|
+
def test_joinAttributeWithUnderscores(self):
|
|
66
|
+
# Make sure that the implicit setting of joinMethodName works
|
|
67
|
+
assert hasattr(ImplicitJoiningSONew, 'foo')
|
|
68
|
+
assert not hasattr(ImplicitJoiningSONew, 'bars')
|
|
69
|
+
|
|
70
|
+
# And make sure explicit setting also works
|
|
71
|
+
assert hasattr(ExplicitJoiningSONew, 'foo')
|
|
72
|
+
assert not hasattr(ExplicitJoiningSONew, 'bars')
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
class PersonJNew2(SQLObject):
|
|
76
|
+
|
|
77
|
+
name = StringCol('name', length=40, alternateID=True)
|
|
78
|
+
addressJ2s = OneToMany('AddressJNew2')
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
class AddressJNew2(SQLObject):
|
|
82
|
+
|
|
83
|
+
class sqlmeta:
|
|
84
|
+
defaultOrder = ['-zip', 'plus4']
|
|
85
|
+
|
|
86
|
+
zip = StringCol(length=5)
|
|
87
|
+
plus4 = StringCol(length=4, default=None)
|
|
88
|
+
personJNew2 = ForeignKey('PersonJNew2')
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
class TestJoin2:
|
|
92
|
+
|
|
93
|
+
def setup_method(self, meth):
|
|
94
|
+
setupClass([PersonJNew2, AddressJNew2])
|
|
95
|
+
p1 = PersonJNew2(name='bob')
|
|
96
|
+
p2 = PersonJNew2(name='sally')
|
|
97
|
+
for z in ['11111', '22222', '33333']:
|
|
98
|
+
AddressJNew2(zip=z, personJNew2=p1)
|
|
99
|
+
AddressJNew2(zip='00000', personJNew2=p2)
|
|
100
|
+
|
|
101
|
+
def test_basic(self):
|
|
102
|
+
bob = PersonJNew2.byName('bob')
|
|
103
|
+
sally = PersonJNew2.byName('sally')
|
|
104
|
+
print(bob.addressJ2s)
|
|
105
|
+
print(bob)
|
|
106
|
+
assert len(list(bob.addressJ2s)) == 3
|
|
107
|
+
assert len(list(sally.addressJ2s)) == 1
|
|
108
|
+
bob.addressJ2s[0].destroySelf()
|
|
109
|
+
assert len(list(bob.addressJ2s)) == 2
|
|
110
|
+
z = bob.addressJ2s[0]
|
|
111
|
+
z.zip = 'xxxxx'
|
|
112
|
+
id = z.id
|
|
113
|
+
del z
|
|
114
|
+
z = AddressJNew2.get(id)
|
|
115
|
+
assert z.zip == 'xxxxx'
|
|
116
|
+
|
|
117
|
+
def test_defaultOrder(self):
|
|
118
|
+
p1 = PersonJNew2.byName('bob')
|
|
119
|
+
assert ([i.zip for i in p1.addressJ2s]
|
|
120
|
+
== ['33333', '22222', '11111'])
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
_personJ3_getters = []
|
|
124
|
+
_personJ3_setters = []
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
class PersonJNew3(SQLObject):
|
|
128
|
+
|
|
129
|
+
name = StringCol('name', length=40, alternateID=True)
|
|
130
|
+
addressJNew3s = OneToMany('AddressJNew3')
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
class AddressJNew3(SQLObject):
|
|
134
|
+
|
|
135
|
+
zip = StringCol(length=5)
|
|
136
|
+
personJNew3 = ForeignKey('PersonJNew3')
|
|
137
|
+
|
|
138
|
+
def _get_personJNew3(self):
|
|
139
|
+
value = self._SO_get_personJNew3()
|
|
140
|
+
_personJ3_getters.append((self, value))
|
|
141
|
+
return value
|
|
142
|
+
|
|
143
|
+
def _set_personJNew3(self, value):
|
|
144
|
+
self._SO_set_personJNew3(value)
|
|
145
|
+
_personJ3_setters.append((self, value))
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
class TestJoin3:
|
|
149
|
+
|
|
150
|
+
def setup_method(self, meth):
|
|
151
|
+
setupClass([PersonJNew3, AddressJNew3])
|
|
152
|
+
p1 = PersonJNew3(name='bob')
|
|
153
|
+
p2 = PersonJNew3(name='sally')
|
|
154
|
+
for z in ['11111', '22222', '33333']:
|
|
155
|
+
AddressJNew3(zip=z, personJNew3=p1)
|
|
156
|
+
AddressJNew3(zip='00000', personJNew3=p2)
|
|
157
|
+
|
|
158
|
+
def test_accessors(self):
|
|
159
|
+
assert len(list(_personJ3_getters)) == 0
|
|
160
|
+
assert len(list(_personJ3_setters)) == 4
|
|
161
|
+
bob = PersonJNew3.byName('bob')
|
|
162
|
+
for addressJ3 in bob.addressJNew3s:
|
|
163
|
+
addressJ3.personJNew3
|
|
164
|
+
assert len(list(_personJ3_getters)) == 3
|
|
165
|
+
assert len(list(_personJ3_setters)) == 4
|