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.
Files changed (149) hide show
  1. sqlobject/__init__.py +15 -0
  2. sqlobject/__version__.py +8 -0
  3. sqlobject/boundattributes.py +124 -0
  4. sqlobject/cache.py +376 -0
  5. sqlobject/classregistry.py +138 -0
  6. sqlobject/col.py +2187 -0
  7. sqlobject/compat.py +59 -0
  8. sqlobject/conftest.py +64 -0
  9. sqlobject/constraints.py +77 -0
  10. sqlobject/converters.py +278 -0
  11. sqlobject/dbconnection.py +1137 -0
  12. sqlobject/dberrors.py +54 -0
  13. sqlobject/declarative.py +211 -0
  14. sqlobject/events.py +365 -0
  15. sqlobject/firebird/__init__.py +8 -0
  16. sqlobject/firebird/firebirdconnection.py +463 -0
  17. sqlobject/include/__init__.py +1 -0
  18. sqlobject/include/hashcol.py +109 -0
  19. sqlobject/include/tests/__init__.py +1 -0
  20. sqlobject/include/tests/test_hashcol.py +84 -0
  21. sqlobject/index.py +189 -0
  22. sqlobject/inheritance/__init__.py +551 -0
  23. sqlobject/inheritance/iteration.py +106 -0
  24. sqlobject/inheritance/tests/__init__.py +1 -0
  25. sqlobject/inheritance/tests/test_aggregates.py +23 -0
  26. sqlobject/inheritance/tests/test_asdict.py +48 -0
  27. sqlobject/inheritance/tests/test_deep_inheritance.py +114 -0
  28. sqlobject/inheritance/tests/test_destroy_cascade.py +23 -0
  29. sqlobject/inheritance/tests/test_foreignKey.py +94 -0
  30. sqlobject/inheritance/tests/test_indexes.py +42 -0
  31. sqlobject/inheritance/tests/test_inheritance.py +164 -0
  32. sqlobject/inheritance/tests/test_inheritance_tree.py +50 -0
  33. sqlobject/joins.py +656 -0
  34. sqlobject/main.py +1880 -0
  35. sqlobject/manager/__init__.py +1 -0
  36. sqlobject/manager/command.py +1309 -0
  37. sqlobject/maxdb/__init__.py +8 -0
  38. sqlobject/maxdb/maxdbconnection.py +320 -0
  39. sqlobject/maxdb/readme.txt +27 -0
  40. sqlobject/mssql/__init__.py +8 -0
  41. sqlobject/mssql/mssqlconnection.py +417 -0
  42. sqlobject/mysql/__init__.py +8 -0
  43. sqlobject/mysql/mysqlconnection.py +562 -0
  44. sqlobject/postgres/__init__.py +8 -0
  45. sqlobject/postgres/pgconnection.py +619 -0
  46. sqlobject/sqlbuilder.py +1655 -0
  47. sqlobject/sqlite/__init__.py +8 -0
  48. sqlobject/sqlite/sqliteconnection.py +418 -0
  49. sqlobject/sresults.py +377 -0
  50. sqlobject/styles.py +174 -0
  51. sqlobject/sybase/__init__.py +8 -0
  52. sqlobject/sybase/sybaseconnection.py +183 -0
  53. sqlobject/tests/__init__.py +1 -0
  54. sqlobject/tests/dbtest.py +363 -0
  55. sqlobject/tests/test_ForeignKey.py +133 -0
  56. sqlobject/tests/test_ForeignKey_cascade.py +150 -0
  57. sqlobject/tests/test_NoneValuedResultItem.py +33 -0
  58. sqlobject/tests/test_SQLMultipleJoin.py +65 -0
  59. sqlobject/tests/test_SQLRelatedJoin.py +114 -0
  60. sqlobject/tests/test_SingleJoin.py +30 -0
  61. sqlobject/tests/test_aggregates.py +75 -0
  62. sqlobject/tests/test_aliases.py +49 -0
  63. sqlobject/tests/test_asdict.py +18 -0
  64. sqlobject/tests/test_auto.py +218 -0
  65. sqlobject/tests/test_basic.py +359 -0
  66. sqlobject/tests/test_blob.py +34 -0
  67. sqlobject/tests/test_boundattributes.py +67 -0
  68. sqlobject/tests/test_cache.py +57 -0
  69. sqlobject/tests/test_class_hash.py +22 -0
  70. sqlobject/tests/test_columns_order.py +18 -0
  71. sqlobject/tests/test_combining_joins.py +47 -0
  72. sqlobject/tests/test_comparison.py +24 -0
  73. sqlobject/tests/test_compat.py +10 -0
  74. sqlobject/tests/test_complex_sorting.py +77 -0
  75. sqlobject/tests/test_constraints.py +43 -0
  76. sqlobject/tests/test_converters.py +276 -0
  77. sqlobject/tests/test_create_drop.py +29 -0
  78. sqlobject/tests/test_csvexport.py +101 -0
  79. sqlobject/tests/test_csvimport.py +21 -0
  80. sqlobject/tests/test_cyclic_reference.py +55 -0
  81. sqlobject/tests/test_datetime.py +171 -0
  82. sqlobject/tests/test_dbconnection.py +17 -0
  83. sqlobject/tests/test_decimal.py +63 -0
  84. sqlobject/tests/test_declarative.py +83 -0
  85. sqlobject/tests/test_default_style.py +65 -0
  86. sqlobject/tests/test_delete.py +74 -0
  87. sqlobject/tests/test_distinct.py +36 -0
  88. sqlobject/tests/test_empty.py +22 -0
  89. sqlobject/tests/test_enum.py +75 -0
  90. sqlobject/tests/test_events.py +142 -0
  91. sqlobject/tests/test_exceptions.py +40 -0
  92. sqlobject/tests/test_expire.py +29 -0
  93. sqlobject/tests/test_groupBy.py +45 -0
  94. sqlobject/tests/test_identity.py +29 -0
  95. sqlobject/tests/test_indexes.py +100 -0
  96. sqlobject/tests/test_inheritance.py +35 -0
  97. sqlobject/tests/test_joins.py +160 -0
  98. sqlobject/tests/test_joins_conditional.py +143 -0
  99. sqlobject/tests/test_jsonbcol.py +53 -0
  100. sqlobject/tests/test_jsoncol.py +56 -0
  101. sqlobject/tests/test_lazy.py +165 -0
  102. sqlobject/tests/test_md5.py +13 -0
  103. sqlobject/tests/test_mysql.py +50 -0
  104. sqlobject/tests/test_new_joins.py +165 -0
  105. sqlobject/tests/test_parse_uri.py +147 -0
  106. sqlobject/tests/test_paste.py +92 -0
  107. sqlobject/tests/test_perConnection.py +20 -0
  108. sqlobject/tests/test_pickle.py +42 -0
  109. sqlobject/tests/test_picklecol.py +44 -0
  110. sqlobject/tests/test_postgres.py +82 -0
  111. sqlobject/tests/test_reparent_sqlmeta.py +33 -0
  112. sqlobject/tests/test_schema.py +30 -0
  113. sqlobject/tests/test_select.py +218 -0
  114. sqlobject/tests/test_select_through.py +63 -0
  115. sqlobject/tests/test_setters.py +23 -0
  116. sqlobject/tests/test_slice.py +59 -0
  117. sqlobject/tests/test_sorting.py +80 -0
  118. sqlobject/tests/test_sqlbuilder.py +134 -0
  119. sqlobject/tests/test_sqlbuilder_dbspecific.py +66 -0
  120. sqlobject/tests/test_sqlbuilder_importproxy.py +55 -0
  121. sqlobject/tests/test_sqlbuilder_joins_instances.py +90 -0
  122. sqlobject/tests/test_sqlite.py +160 -0
  123. sqlobject/tests/test_sqlmeta_idName.py +52 -0
  124. sqlobject/tests/test_sqlobject_admin.py +38 -0
  125. sqlobject/tests/test_string_id.py +79 -0
  126. sqlobject/tests/test_style.py +36 -0
  127. sqlobject/tests/test_subqueries.py +142 -0
  128. sqlobject/tests/test_transactions.py +122 -0
  129. sqlobject/tests/test_unicode.py +84 -0
  130. sqlobject/tests/test_uuidcol.py +40 -0
  131. sqlobject/tests/test_validation.py +125 -0
  132. sqlobject/tests/test_views.py +159 -0
  133. sqlobject/util/__init__.py +1 -0
  134. sqlobject/util/csvexport.py +210 -0
  135. sqlobject/util/csvimport.py +366 -0
  136. sqlobject/util/moduleloader.py +35 -0
  137. sqlobject/util/threadinglocal.py +6 -0
  138. sqlobject/versioning/__init__.py +120 -0
  139. sqlobject/versioning/test/__init__.py +0 -0
  140. sqlobject/versioning/test/test_version.py +183 -0
  141. sqlobject/views.py +151 -0
  142. sqlobject/wsgi_middleware.py +109 -0
  143. sqlobject-3.13.1.data/scripts/sqlobject-admin +36 -0
  144. sqlobject-3.13.1.data/scripts/sqlobject-convertOldURI +19 -0
  145. sqlobject-3.13.1.dist-info/METADATA +177 -0
  146. sqlobject-3.13.1.dist-info/RECORD +149 -0
  147. sqlobject-3.13.1.dist-info/WHEEL +6 -0
  148. sqlobject-3.13.1.dist-info/entry_points.txt +4 -0
  149. sqlobject-3.13.1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,218 @@
1
+ import pytest
2
+ from sqlobject import IntCol, LIKE, RLIKE, SQLObject, \
3
+ SQLObjectIntegrityError, SQLObjectNotFound, StringCol
4
+ from sqlobject.sqlbuilder import func
5
+ from .dbtest import raises, setupClass, supports, setSQLiteConnectionFactory
6
+
7
+
8
+ class IterTest(SQLObject):
9
+ name = StringCol(dbName='name_col', length=200)
10
+
11
+
12
+ names = ('a', 'b', 'c')
13
+
14
+
15
+ def setupIter():
16
+ setupClass(IterTest)
17
+ for n in names:
18
+ IterTest(name=n)
19
+
20
+
21
+ def test_00_normal():
22
+ setupIter()
23
+ count = 0
24
+ for test in IterTest.select():
25
+ count += 1
26
+ assert count == len(names)
27
+
28
+
29
+ def test_00b_lazy():
30
+ setupIter()
31
+ count = 0
32
+ for test in IterTest.select(lazyColumns=True):
33
+ count += 1
34
+ assert count == len(names)
35
+
36
+
37
+ def test_01_turn_to_list():
38
+ count = 0
39
+ for test in list(IterTest.select()):
40
+ count += 1
41
+ assert count == len(names)
42
+
43
+
44
+ def test_02_generator():
45
+ all = IterTest.select()
46
+ count = 0
47
+ for i, test in enumerate(all):
48
+ count += 1
49
+ assert count == len(names)
50
+
51
+
52
+ def test_03_ranged_indexed():
53
+ all = IterTest.select()
54
+ count = 0
55
+ for i in range(all.count()):
56
+ all[i] # test it's there
57
+ count += 1
58
+ assert count == len(names)
59
+
60
+
61
+ def test_04_indexed_ended_by_exception():
62
+ if not supports('limitSelect'):
63
+ pytest.skip("limitSelect isn't supported")
64
+ all = IterTest.select()
65
+ count = 0
66
+ try:
67
+ while 1:
68
+ all[count]
69
+ count += 1
70
+ # Stop the test if it's gone on too long
71
+ if count > len(names):
72
+ break
73
+ except IndexError:
74
+ pass
75
+ assert count == len(names)
76
+
77
+
78
+ def test_05_select_limit():
79
+ setupIter()
80
+ assert len(list(IterTest.select(limit=2))) == 2
81
+ raises(AssertionError, IterTest.select(limit=2).count)
82
+
83
+
84
+ def test_06_contains():
85
+ setupIter()
86
+ assert len(list(IterTest.select(IterTest.q.name.startswith('a')))) == 1
87
+ assert len(list(IterTest.select(IterTest.q.name.contains('a')))) == 1
88
+ assert len(list(IterTest.select(
89
+ IterTest.q.name.contains(func.lower('A'))))) == 1
90
+ assert len(list(IterTest.select(IterTest.q.name.contains("a'b")))) == 0
91
+ assert len(list(IterTest.select(IterTest.q.name.endswith('a')))) == 1
92
+
93
+
94
+ def test_07_contains_special():
95
+ setupClass(IterTest)
96
+ a = IterTest(name='\\test')
97
+ b = IterTest(name='100%')
98
+ c = IterTest(name='test_')
99
+ assert list(IterTest.select(IterTest.q.name.startswith('\\'))) == [a]
100
+ assert list(IterTest.select(IterTest.q.name.contains('%'))) == [b]
101
+ assert list(IterTest.select(IterTest.q.name.endswith('_'))) == [c]
102
+
103
+
104
+ def test_select_getOne():
105
+ setupClass(IterTest)
106
+ a = IterTest(name='a')
107
+ b = IterTest(name='b')
108
+ assert IterTest.selectBy(name='a').getOne() == a
109
+ assert IterTest.select(IterTest.q.name == 'b').getOne() == b
110
+ assert IterTest.selectBy(name='c').getOne(None) is None
111
+ raises(SQLObjectNotFound, IterTest.selectBy(name="c").getOne)
112
+ IterTest(name='b')
113
+ raises(SQLObjectIntegrityError, IterTest.selectBy(name="b").getOne)
114
+ raises(SQLObjectIntegrityError, IterTest.selectBy(name="b").getOne, None)
115
+
116
+
117
+ def test_selectBy():
118
+ setupClass(IterTest)
119
+ IterTest(name='a')
120
+ IterTest(name='b')
121
+ assert IterTest.selectBy().count() == 2
122
+
123
+
124
+ def test_selectBy_kwargs():
125
+ setupClass(IterTest)
126
+ raises(TypeError, IterTest, nonexistant='b')
127
+
128
+
129
+ class UniqTest(SQLObject):
130
+ name = StringCol(dbName='name_col', unique=True, length=100)
131
+
132
+
133
+ def test_by_uniq():
134
+ setupClass(UniqTest)
135
+ a = UniqTest(name='a')
136
+ b = UniqTest(name='b')
137
+ assert UniqTest.byName('a') is a
138
+ assert UniqTest.byName('b') is b
139
+
140
+
141
+ class Counter2(SQLObject):
142
+
143
+ n1 = IntCol(notNull=True)
144
+ n2 = IntCol(notNull=True)
145
+
146
+
147
+ class TestSelect:
148
+
149
+ def setup_method(self, meth):
150
+ setupClass(Counter2)
151
+ for i in range(10):
152
+ for j in range(10):
153
+ Counter2(n1=i, n2=j)
154
+
155
+ def counterEqual(self, counters, value):
156
+ assert [(c.n1, c.n2) for c in counters] == value
157
+
158
+ def accumulateEqual(self, func, counters, value):
159
+ assert func([c.n1 for c in counters]) == value
160
+
161
+ def test_1(self):
162
+ self.accumulateEqual(sum, Counter2.select(orderBy='n1'),
163
+ sum(range(10)) * 10)
164
+
165
+ def test_2(self):
166
+ self.accumulateEqual(len, Counter2.select('all'), 100)
167
+
168
+
169
+ def test_select_LIKE():
170
+ setupClass(IterTest)
171
+ IterTest(name='sqlobject')
172
+ IterTest(name='sqlbuilder')
173
+ assert IterTest.select(LIKE(IterTest.q.name, "sql%")).count() == 2
174
+ assert IterTest.select(LIKE(IterTest.q.name, "sqlb%")).count() == 1
175
+ assert IterTest.select(LIKE(IterTest.q.name, "sqlb%")).count() == 1
176
+ assert IterTest.select(LIKE(IterTest.q.name, "sqlx%")).count() == 0
177
+
178
+
179
+ def test_select_RLIKE():
180
+ if not supports('rlike'):
181
+ pytest.skip("rlike isn't supported")
182
+
183
+ setupClass(IterTest)
184
+
185
+ if IterTest._connection.dbName == "sqlite":
186
+ # Implement regexp() function for SQLite
187
+ import re
188
+
189
+ def regexp(regexp, test):
190
+ return bool(re.search(regexp, test))
191
+
192
+ def SQLiteConnectionFactory(sqlite):
193
+ class MyConnection(sqlite.Connection):
194
+ def __init__(self, *args, **kwargs):
195
+ super(MyConnection, self).__init__(*args, **kwargs)
196
+ self.create_function("regexp", 2, regexp)
197
+ return MyConnection
198
+
199
+ setSQLiteConnectionFactory(IterTest, SQLiteConnectionFactory)
200
+
201
+ IterTest(name='sqlobject')
202
+ IterTest(name='sqlbuilder')
203
+ assert IterTest.select(RLIKE(IterTest.q.name, "^sql.*$")).count() == 2
204
+ assert IterTest.select(RLIKE(IterTest.q.name, "^sqlb.*$")).count() == 1
205
+ assert IterTest.select(RLIKE(IterTest.q.name, "^sqlb.*$")).count() == 1
206
+ assert IterTest.select(RLIKE(IterTest.q.name, "^sqlx.*$")).count() == 0
207
+
208
+
209
+ def test_select_sqlbuilder():
210
+ setupClass(IterTest)
211
+ IterTest(name='sqlobject')
212
+ IterTest.select(IterTest.q.name == u'sqlobject')
213
+
214
+
215
+ def test_select_perConnection():
216
+ setupClass(IterTest)
217
+ IterTest(name='a')
218
+ assert not IterTest.select().getOne().sqlmeta._perConnection
@@ -0,0 +1,63 @@
1
+ import pytest
2
+ from sqlobject import ForeignKey, SQLMultipleJoin, SQLObject, SQLRelatedJoin, \
3
+ StringCol
4
+ from sqlobject.tests.dbtest import inserts, setupClass
5
+
6
+
7
+ # Tests retrieving objects through a join/fk on a selectResults
8
+
9
+
10
+ class SRThrough1(SQLObject):
11
+ three = ForeignKey('SRThrough3')
12
+ twos = SQLMultipleJoin('SRThrough2', joinColumn='oneID')
13
+
14
+
15
+ class SRThrough2(SQLObject):
16
+ one = ForeignKey('SRThrough1')
17
+ threes = SQLRelatedJoin('SRThrough3', addRemoveName='Three')
18
+
19
+
20
+ class SRThrough3(SQLObject):
21
+ name = StringCol()
22
+ ones = SQLMultipleJoin('SRThrough1', joinColumn='threeID')
23
+ twos = SQLRelatedJoin('SRThrough2')
24
+
25
+
26
+ def setup_module(mod):
27
+ global ones, twos, threes
28
+ setupClass([SRThrough3, SRThrough1, SRThrough2])
29
+ threes = inserts(SRThrough3,
30
+ [('a',), ('b',), ('c',)],
31
+ 'name')
32
+ ones = inserts(SRThrough1,
33
+ [(threes[0].id,), (threes[0].id,), (threes[2].id,)],
34
+ 'threeID')
35
+ twos = inserts(SRThrough2,
36
+ [(ones[0].id,), (ones[1].id,), (ones[2].id,)],
37
+ 'oneID')
38
+ twos[0].addThree(threes[0])
39
+ twos[0].addThree(threes[1])
40
+
41
+
42
+ def testBadRef():
43
+ with pytest.raises(AttributeError):
44
+ threes[0].throughTo.four
45
+
46
+
47
+ def testThroughFK():
48
+ assert list(threes[0].ones.throughTo.three) == [threes[0]]
49
+
50
+
51
+ def testThroughMultipleJoin():
52
+ assert list(threes[0].ones.throughTo.twos) == [twos[0], twos[1]]
53
+
54
+
55
+ def testThroughRelatedJoin():
56
+ assert list(threes[0].twos.throughTo.threes) == [threes[0], threes[1]]
57
+ assert list(
58
+ SRThrough3.select(SRThrough3.q.id == threes[0].id).throughTo.twos) == \
59
+ list(threes[0].twos)
60
+
61
+
62
+ def testThroughFKAndJoin():
63
+ assert list(threes[0].ones.throughTo.three.throughTo.twos) == [twos[0]]
@@ -0,0 +1,23 @@
1
+ from sqlobject import SQLObject, StringCol
2
+ from sqlobject.tests.dbtest import setupClass
3
+
4
+
5
+ class SOTestSetters(SQLObject):
6
+ firstName = StringCol(length=50, dbName='fname_col', default=None)
7
+ lastName = StringCol(length=50, dbName='lname_col', default=None)
8
+
9
+ def _set_name(self, v):
10
+ firstName, lastName = v.split()
11
+ self.firstName = firstName
12
+ self.lastName = lastName
13
+
14
+ def _get_name(self):
15
+ return "%s %s" % (self.firstName, self.lastName)
16
+
17
+
18
+ def test_create():
19
+ setupClass(SOTestSetters)
20
+ t = SOTestSetters(name='John Doe')
21
+ assert t.firstName == 'John'
22
+ assert t.lastName == 'Doe'
23
+ assert t.name == 'John Doe'
@@ -0,0 +1,59 @@
1
+ import pytest
2
+ from sqlobject import IntCol, SQLObject
3
+ from sqlobject.tests.dbtest import setupClass, supports
4
+
5
+
6
+ ########################################
7
+ # Slicing tests
8
+ ########################################
9
+
10
+
11
+ def listrange(*args):
12
+ """Always return a list, for py3k compatibility"""
13
+ return list(range(*args))
14
+
15
+
16
+ class Counter(SQLObject):
17
+
18
+ number = IntCol(notNull=True)
19
+
20
+
21
+ class TestSlice:
22
+
23
+ def setup_method(self, meth):
24
+ setupClass(Counter)
25
+ for i in range(100):
26
+ Counter(number=i)
27
+
28
+ def counterEqual(self, counters, value):
29
+ if not supports('limitSelect'):
30
+ pytest.skip("limitSelect isn't supported")
31
+ assert [c.number for c in counters] == value
32
+
33
+ def test_slice(self):
34
+ self.counterEqual(
35
+ Counter.select(None, orderBy='number'), listrange(100))
36
+
37
+ self.counterEqual(
38
+ Counter.select(None, orderBy='number')[10:20],
39
+ listrange(10, 20))
40
+
41
+ self.counterEqual(
42
+ Counter.select(None, orderBy='number')[20:30][:5],
43
+ listrange(20, 25))
44
+
45
+ self.counterEqual(
46
+ Counter.select(None, orderBy='number')[20:30][1:5],
47
+ listrange(21, 25))
48
+
49
+ self.counterEqual(
50
+ Counter.select(None, orderBy='number')[:-10],
51
+ listrange(0, 90))
52
+
53
+ self.counterEqual(
54
+ Counter.select(None, orderBy='number', reversed=True),
55
+ listrange(99, -1, -1))
56
+
57
+ self.counterEqual(
58
+ Counter.select(None, orderBy='-number'),
59
+ listrange(99, -1, -1))
@@ -0,0 +1,80 @@
1
+ from sqlobject import DESC, SQLObject, StringCol, sqlmeta
2
+ from sqlobject.tests.dbtest import inserts, setupClass
3
+
4
+
5
+ class Names(SQLObject):
6
+
7
+ class sqlmeta(sqlmeta):
8
+ table = 'names_table'
9
+ defaultOrder = ['lastName', 'firstName']
10
+
11
+ firstName = StringCol(length=30)
12
+ lastName = StringCol(length=30)
13
+
14
+
15
+ def setupNames():
16
+ setupClass(Names)
17
+ inserts(Names, [('aj', 'baker'), ('joe', 'robbins'),
18
+ ('tim', 'jackson'), ('joe', 'baker'),
19
+ ('zoe', 'robbins')],
20
+ schema='firstName lastName')
21
+
22
+
23
+ def nameList(names):
24
+ result = []
25
+ for name in names:
26
+ result.append('%s %s' % (name.firstName, name.lastName))
27
+ return result
28
+
29
+
30
+ def firstList(names):
31
+ return [n.firstName for n in names]
32
+
33
+
34
+ def test_defaultOrder():
35
+ setupNames()
36
+ assert nameList(Names.select()) == \
37
+ ['aj baker', 'joe baker',
38
+ 'tim jackson', 'joe robbins',
39
+ 'zoe robbins']
40
+
41
+
42
+ def test_otherOrder():
43
+ setupNames()
44
+ assert nameList(Names.select().orderBy(['firstName', 'lastName'])) == \
45
+ ['aj baker', 'joe baker',
46
+ 'joe robbins', 'tim jackson',
47
+ 'zoe robbins']
48
+
49
+
50
+ def test_untranslatedColumnOrder():
51
+ setupNames()
52
+ assert nameList(Names.select().orderBy(['first_name', 'last_name'])) == \
53
+ ['aj baker', 'joe baker',
54
+ 'joe robbins', 'tim jackson',
55
+ 'zoe robbins']
56
+
57
+
58
+ def test_singleUntranslatedColumnOrder():
59
+ setupNames()
60
+ assert firstList(Names.select().orderBy('firstName')) == \
61
+ ['aj', 'joe', 'joe', 'tim', 'zoe']
62
+ assert firstList(Names.select().orderBy('first_name')) == \
63
+ ['aj', 'joe', 'joe', 'tim', 'zoe']
64
+ assert firstList(Names.select().orderBy('-firstName')) == \
65
+ ['zoe', 'tim', 'joe', 'joe', 'aj']
66
+ assert firstList(Names.select().orderBy(u'-first_name')) == \
67
+ ['zoe', 'tim', 'joe', 'joe', 'aj']
68
+ assert firstList(Names.select().orderBy(Names.q.firstName)) == \
69
+ ['aj', 'joe', 'joe', 'tim', 'zoe']
70
+ assert firstList(Names.select().orderBy('firstName').reversed()) == \
71
+ ['zoe', 'tim', 'joe', 'joe', 'aj']
72
+ assert firstList(Names.select().orderBy('-firstName').reversed()) == \
73
+ ['aj', 'joe', 'joe', 'tim', 'zoe']
74
+ assert firstList(Names.select().orderBy(DESC(Names.q.firstName))) == \
75
+ ['zoe', 'tim', 'joe', 'joe', 'aj']
76
+ assert firstList(Names.select().orderBy(Names.q.firstName).reversed()) == \
77
+ ['zoe', 'tim', 'joe', 'joe', 'aj']
78
+ assert firstList(
79
+ Names.select().orderBy(DESC(Names.q.firstName)).reversed()) == \
80
+ ['aj', 'joe', 'joe', 'tim', 'zoe']
@@ -0,0 +1,134 @@
1
+ from sqlobject import IntCol, SQLObject, StringCol
2
+ from sqlobject.compat import PY2
3
+ from sqlobject.sqlbuilder import AND, ANY, CONCAT, Delete, Insert, \
4
+ SQLOp, Select, Union, Update, const, func, sqlrepr
5
+ from sqlobject.tests.dbtest import getConnection, raises, setupClass
6
+
7
+
8
+ class SOTestSQLBuilder(SQLObject):
9
+ name = StringCol()
10
+ so_value = IntCol()
11
+
12
+
13
+ def test_Select():
14
+ setupClass(SOTestSQLBuilder)
15
+
16
+ select1 = Select([const.id, func.MAX(const.salary)],
17
+ staticTables=['employees'])
18
+ assert sqlrepr(select1) == 'SELECT id, MAX(salary) FROM employees'
19
+
20
+ select2 = Select([SOTestSQLBuilder.q.name, SOTestSQLBuilder.q.so_value])
21
+ assert sqlrepr(select2) == \
22
+ 'SELECT so_test_sql_builder.name, so_test_sql_builder.so_value ' \
23
+ 'FROM so_test_sql_builder'
24
+
25
+ union = Union(select1, select2)
26
+ assert sqlrepr(union) == \
27
+ 'SELECT id, MAX(salary) FROM employees ' \
28
+ 'UNION SELECT so_test_sql_builder.name, ' \
29
+ 'so_test_sql_builder.so_value ' \
30
+ 'FROM so_test_sql_builder'
31
+
32
+ union = Union(SOTestSQLBuilder.select().queryForSelect())
33
+ assert sqlrepr(union) == \
34
+ 'SELECT so_test_sql_builder.id, so_test_sql_builder.name, ' \
35
+ 'so_test_sql_builder.so_value FROM so_test_sql_builder WHERE 1 = 1'
36
+
37
+
38
+ def test_empty_AND():
39
+ assert AND() is None
40
+ assert AND(True) is True
41
+
42
+ # sqlrepr() is needed because AND() returns an SQLExpression that overrides
43
+ # comparison. The following
44
+ # AND('x', 'y') == "foo bar"
45
+ # is True! (-: Eeek!
46
+ assert sqlrepr(AND(1, 2)) == sqlrepr(SQLOp("AND", 1, 2)) == "((1) AND (2))"
47
+ assert sqlrepr(AND(1, 2, '3'), "sqlite") == \
48
+ sqlrepr(SQLOp("AND", 1, SQLOp("AND", 2, '3')), "sqlite") == \
49
+ "((1) AND ((2) AND ('3')))"
50
+
51
+
52
+ def test_modulo():
53
+ setupClass(SOTestSQLBuilder)
54
+ assert sqlrepr(SOTestSQLBuilder.q.so_value % 2 == 0, 'mysql') == \
55
+ "((MOD(so_test_sql_builder.so_value, 2)) = (0))"
56
+ assert sqlrepr(SOTestSQLBuilder.q.so_value % 2 == 0, 'sqlite') == \
57
+ "(((so_test_sql_builder.so_value) % (2)) = (0))"
58
+
59
+
60
+ def test_division():
61
+ SOTestSQLBuilder(name='test', so_value=-11)
62
+ assert sqlrepr(SOTestSQLBuilder.q.so_value / 4 == -2.75, 'mysql') == \
63
+ "(((so_test_sql_builder.so_value) / (4)) = (-2.75))"
64
+ assert sqlrepr(SOTestSQLBuilder.q.so_value // 4 == -3, 'mysql') == \
65
+ "((FLOOR(((so_test_sql_builder.so_value) / (4)))) = (-3))"
66
+
67
+
68
+ def test_str_or_sqlrepr():
69
+ select = Select(['id', 'name'], staticTables=['employees'],
70
+ where='value>0', orderBy='id')
71
+ assert sqlrepr(select, 'sqlite') == \
72
+ 'SELECT id, name FROM employees WHERE value>0 ORDER BY id'
73
+
74
+ select = Select(['id', 'name'], staticTables=['employees'],
75
+ where='value>0', orderBy='id', lazyColumns=True)
76
+ assert sqlrepr(select, 'sqlite') == \
77
+ 'SELECT id FROM employees WHERE value>0 ORDER BY id'
78
+
79
+ insert = Insert('employees', values={'id': 1, 'name': 'test'})
80
+ assert sqlrepr(insert, 'sqlite') == \
81
+ "INSERT INTO employees (id, name) VALUES (1, 'test')"
82
+
83
+ update = Update('employees', {'name': 'test'}, where='id=1')
84
+ assert sqlrepr(update, 'sqlite') == \
85
+ "UPDATE employees SET name='test' WHERE id=1"
86
+
87
+ update = Update('employees', {'name': 'test', 'age': 42}, where='id=1')
88
+ assert sqlrepr(update, 'sqlite') == \
89
+ "UPDATE employees SET age=42, name='test' WHERE id=1"
90
+
91
+ delete = Delete('employees', where='id=1')
92
+ assert sqlrepr(delete, 'sqlite') == \
93
+ "DELETE FROM employees WHERE id=1"
94
+
95
+ raises(TypeError, Delete, 'employees')
96
+
97
+ delete = Delete('employees', where=None)
98
+ assert sqlrepr(delete, 'sqlite') == \
99
+ "DELETE FROM employees"
100
+
101
+
102
+ def test_CONCAT():
103
+ setupClass(SOTestSQLBuilder)
104
+ SOTestSQLBuilder(name='test', so_value=42)
105
+
106
+ assert sqlrepr(CONCAT('a', 'b'), 'mysql') == "CONCAT('a', 'b')"
107
+ assert sqlrepr(CONCAT('a', 'b'), 'mssql') == "'a' + 'b'"
108
+ assert sqlrepr(CONCAT('a', 'b'), 'sqlite') == "'a' || 'b'"
109
+ assert sqlrepr(CONCAT('prefix', SOTestSQLBuilder.q.name), 'mysql') == \
110
+ "CONCAT('prefix', so_test_sql_builder.name)"
111
+ assert sqlrepr(CONCAT('prefix', SOTestSQLBuilder.q.name), 'sqlite') == \
112
+ "'prefix' || so_test_sql_builder.name"
113
+
114
+ select = Select([CONCAT(SOTestSQLBuilder.q.name, '-suffix')],
115
+ staticTables=['so_test_sql_builder'])
116
+ connection = getConnection()
117
+ rows = connection.queryAll(connection.sqlrepr(select))
118
+ result = rows[0][0]
119
+ if not PY2 and not isinstance(result, str):
120
+ result = result.decode('ascii')
121
+ assert result == "test-suffix"
122
+
123
+
124
+ def test_ANY():
125
+ setupClass(SOTestSQLBuilder)
126
+
127
+ select = Select(
128
+ [SOTestSQLBuilder.q.name],
129
+ 'value' == ANY(SOTestSQLBuilder.q.so_value),
130
+ )
131
+
132
+ assert sqlrepr(select, 'mysql') == \
133
+ "SELECT so_test_sql_builder.name FROM so_test_sql_builder " \
134
+ "WHERE (('value') = ANY (so_test_sql_builder.so_value))"
@@ -0,0 +1,66 @@
1
+ from __future__ import print_function
2
+
3
+ from sqlobject import BoolCol, SQLObject
4
+ from sqlobject.sqlbuilder import AND, Alias, EXISTS, JOIN, LEFTJOINOn, \
5
+ Select, sqlrepr
6
+ from sqlobject.tests.dbtest import setupClass
7
+
8
+ ''' Going to test that complex sqlbuilder constructions are never
9
+ prematurely stringified. A straight-forward approach is to use
10
+ Bools, since postgresql wants special formatting in queries.
11
+ The test is whether a call to sqlrepr(x, 'postgres') includes
12
+ the appropriate bool formatting throughout.
13
+ '''
14
+
15
+
16
+ class SBButton(SQLObject):
17
+ activated = BoolCol()
18
+
19
+
20
+ def makeClause():
21
+ # It's not a comparison, it's an SQLExpression
22
+ return SBButton.q.activated == True # noqa
23
+
24
+
25
+ def makeSelect():
26
+ return Select(SBButton.q.id, clause=makeClause())
27
+
28
+
29
+ def checkCount(q, c, msg=''):
30
+ print("STRING:", str(q))
31
+ print("POSTGR:", sqlrepr(q, 'postgres'))
32
+ assert sqlrepr(q, 'postgres').count("'t'") == c and \
33
+ sqlrepr(q, 'postgres') != str(q), msg
34
+
35
+
36
+ def testSimple():
37
+ setupClass(SBButton)
38
+ checkCount(makeClause(), 1)
39
+ checkCount(makeSelect(), 1)
40
+
41
+
42
+ def testMiscOps():
43
+ setupClass(SBButton)
44
+ checkCount(AND(makeClause(), makeClause()), 2)
45
+ checkCount(AND(makeClause(), EXISTS(makeSelect())), 2)
46
+
47
+
48
+ def testAliased():
49
+ setupClass(SBButton)
50
+ b = Alias(makeSelect(), 'b')
51
+ checkCount(b, 1)
52
+ checkCount(Select(b.q.id), 1)
53
+
54
+ # Table1 & Table2 are treated individually in joins
55
+ checkCount(JOIN(None, b), 1)
56
+ checkCount(JOIN(b, SBButton), 1)
57
+ checkCount(JOIN(SBButton, b), 1)
58
+ checkCount(LEFTJOINOn(None, b, SBButton.q.id == b.q.id), 1)
59
+ checkCount(LEFTJOINOn(b, SBButton, SBButton.q.id == b.q.id), 1)
60
+ checkCount(LEFTJOINOn(SBButton, b, SBButton.q.id == b.q.id), 1)
61
+
62
+
63
+ def testTablesUsedSResults():
64
+ setupClass(SBButton)
65
+
66
+ checkCount(SBButton.select(makeClause()).queryForSelect(), 1)
@@ -0,0 +1,55 @@
1
+ from sqlobject import SQLObject, StringCol
2
+ from sqlobject.sqlbuilder import Alias, ImportProxy, tablesUsedSet
3
+ from sqlobject.views import ViewSQLObject
4
+
5
+
6
+ def testSimple():
7
+ nyi = ImportProxy('NotYetImported')
8
+ x = nyi.q.name
9
+
10
+ class NotYetImported(SQLObject):
11
+ name = StringCol(dbName='a_name')
12
+
13
+ y = nyi.q.name
14
+
15
+ assert str(x) == 'not_yet_imported.a_name'
16
+ assert str(y) == 'not_yet_imported.a_name'
17
+
18
+
19
+ def testAddition():
20
+ nyi = ImportProxy('NotYetImported2')
21
+ x = nyi.q.name + nyi.q.name
22
+
23
+ class NotYetImported2(SQLObject):
24
+ name = StringCol(dbName='a_name')
25
+
26
+ assert str(x) == \
27
+ '((not_yet_imported2.a_name) + (not_yet_imported2.a_name))'
28
+
29
+
30
+ def testOnView():
31
+ nyi = ImportProxy('NotYetImportedV')
32
+ x = nyi.q.name
33
+
34
+ class NotYetImported3(SQLObject):
35
+ name = StringCol(dbName='a_name')
36
+
37
+ class NotYetImportedV(ViewSQLObject):
38
+ class sqlmeta:
39
+ idName = NotYetImported3.q.id
40
+ name = StringCol(dbName=NotYetImported3.q.name)
41
+
42
+ assert str(x) == 'not_yet_imported_v.name'
43
+
44
+
45
+ def testAlias():
46
+ nyi = ImportProxy('NotYetImported4')
47
+ y = Alias(nyi, 'y')
48
+ x = y.q.name
49
+
50
+ class NotYetImported4(SQLObject):
51
+ name = StringCol(dbName='a_name')
52
+
53
+ assert str(y) == 'not_yet_imported4 y'
54
+ assert tablesUsedSet(x, None) == set(['not_yet_imported4 y'])
55
+ assert str(x) == 'y.a_name'