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,122 @@
1
+ import pytest
2
+ from sqlobject import SQLObject, SQLObjectNotFound, StringCol
3
+ from sqlobject.tests.dbtest import raises, setupClass, supports
4
+ from sqlobject import events
5
+ from sqlobject.main import sqlmeta
6
+
7
+ ########################################
8
+ # Transaction test
9
+ ########################################
10
+
11
+
12
+ try:
13
+ support_transactions = supports('transactions')
14
+ except NameError:
15
+ # The module was imported during documentation building
16
+ pass
17
+ else:
18
+ if not support_transactions:
19
+ pytestmark = pytest.mark.skip("These tests require transactions")
20
+
21
+
22
+ class SOTestSOTrans(SQLObject):
23
+ class sqlmeta:
24
+ defaultOrder = 'name'
25
+ name = StringCol(length=10, alternateID=True, dbName='name_col')
26
+
27
+
28
+ def make_watcher():
29
+ log = []
30
+
31
+ def watch(*args):
32
+ log.append(args)
33
+
34
+ watch.log = log
35
+ return watch
36
+
37
+
38
+ def make_listen(signal):
39
+ watcher = make_watcher()
40
+ events.listen(watcher, sqlmeta, signal)
41
+ return watcher
42
+
43
+
44
+ def test_transaction():
45
+ commit_watcher = make_listen(events.CommitSignal)
46
+ rollback_watcher = make_listen(events.RollbackSignal)
47
+ setupClass(SOTestSOTrans)
48
+ SOTestSOTrans(name='bob')
49
+ SOTestSOTrans(name='tim')
50
+ trans = SOTestSOTrans._connection.transaction()
51
+ try:
52
+ SOTestSOTrans._connection.autoCommit = 'exception'
53
+ SOTestSOTrans(name='joe', connection=trans)
54
+ trans.rollback()
55
+ trans.begin()
56
+ assert ([n.name for n in SOTestSOTrans.select(connection=trans)]
57
+ == ['bob', 'tim'])
58
+ b = SOTestSOTrans.byName('bob', connection=trans)
59
+ b.name = 'robert'
60
+ trans.commit()
61
+ assert b.name == 'robert'
62
+ b.name = 'bob'
63
+ trans.rollback()
64
+ trans.begin()
65
+ assert b.name == 'robert'
66
+ assert len(commit_watcher.log) == 1
67
+ assert commit_watcher.log[0][0][0][0] == 'SOTestSOTrans'
68
+ assert commit_watcher.log[0][0][0][1] == [1, 2]
69
+ assert len(rollback_watcher.log) == 2
70
+ assert rollback_watcher.log[0][0][0][0] == 'SOTestSOTrans'
71
+ assert rollback_watcher.log[0][0][0][1] == [3]
72
+ assert rollback_watcher.log[1][0][0][0] == 'SOTestSOTrans'
73
+ assert rollback_watcher.log[1][0][0][1] == [1, 2]
74
+ finally:
75
+ SOTestSOTrans._connection.autoCommit = True
76
+
77
+
78
+ def test_transaction_commit_sync():
79
+ setupClass(SOTestSOTrans)
80
+ connection = SOTestSOTrans._connection
81
+ trans = connection.transaction()
82
+ try:
83
+ SOTestSOTrans(name='bob')
84
+ bOut = SOTestSOTrans.byName('bob')
85
+ bIn = SOTestSOTrans.byName('bob', connection=trans)
86
+ bIn.name = 'robert'
87
+ assert bOut.name == 'bob'
88
+ trans.commit()
89
+ assert bOut.name == 'robert'
90
+ finally:
91
+ trans.rollback()
92
+ connection.autoCommit = True
93
+ connection.close()
94
+
95
+
96
+ def test_transaction_delete(close=False):
97
+ setupClass(SOTestSOTrans)
98
+ connection = SOTestSOTrans._connection
99
+ if (connection.dbName == 'sqlite') and connection._memory:
100
+ pytest.skip("The test doesn't work with sqlite memory connection")
101
+ trans = connection.transaction()
102
+ try:
103
+ SOTestSOTrans(name='bob')
104
+ bIn = SOTestSOTrans.byName('bob', connection=trans)
105
+ bIn.destroySelf()
106
+ bOut = SOTestSOTrans.select(SOTestSOTrans.q.name == 'bob')
107
+ assert bOut.count() == 1
108
+ bOutInst = bOut[0]
109
+ bOutID = bOutInst.id # noqa: bOutID is used in the string code below
110
+ trans.commit(close=close)
111
+ assert bOut.count() == 0
112
+ raises(SQLObjectNotFound, SOTestSOTrans.get, bOutID)
113
+ with raises(SQLObjectNotFound):
114
+ bOutInst.name
115
+ finally:
116
+ trans.rollback()
117
+ connection.autoCommit = True
118
+ connection.close()
119
+
120
+
121
+ def test_transaction_delete_with_close():
122
+ test_transaction_delete(close=True)
@@ -0,0 +1,84 @@
1
+ from sqlobject import IntCol, SQLObject, UnicodeCol
2
+ from sqlobject.compat import PY2
3
+ from sqlobject.tests.dbtest import setupClass
4
+
5
+
6
+ ########################################
7
+ # Unicode columns
8
+ ########################################
9
+
10
+
11
+ class SOTestUnicode(SQLObject):
12
+ so_count = IntCol(alternateID=True)
13
+ col = UnicodeCol(alternateID=True, length=100)
14
+
15
+
16
+ data = [u'\u00f0', u'test', 'ascii test']
17
+ items = []
18
+
19
+
20
+ def setup():
21
+ global items
22
+ items = []
23
+ setupClass(SOTestUnicode)
24
+ for i, s in enumerate(data):
25
+ items.append(SOTestUnicode(so_count=i, col=s))
26
+
27
+
28
+ def test_create():
29
+ setup()
30
+ for s, item in zip(data, items):
31
+ assert item.col == s
32
+
33
+ conn = SOTestUnicode._connection
34
+ if PY2:
35
+ rows = conn.queryAll("""
36
+ SELECT so_count, col
37
+ FROM so_test_unicode
38
+ ORDER BY so_count
39
+ """)
40
+ for so_count, col in rows:
41
+ if not isinstance(col, bytes):
42
+ col = col.encode('utf-8')
43
+ assert data[so_count].encode('utf-8') == col
44
+ else:
45
+ rows = conn.queryAll("""
46
+ SELECT so_count, col
47
+ FROM so_test_unicode
48
+ ORDER BY so_count
49
+ """)
50
+ # On python 3, everthings already decoded to unicode
51
+ for so_count, col in rows:
52
+ assert data[so_count] == col
53
+
54
+
55
+ def test_select():
56
+ setup()
57
+ for i, value in enumerate(data):
58
+ rows = list(SOTestUnicode.select(SOTestUnicode.q.col == value))
59
+ assert len(rows) == 1
60
+ if PY2:
61
+ rows = list(SOTestUnicode.select(SOTestUnicode.q.col == value))
62
+ assert len(rows) == 1
63
+ rows = list(SOTestUnicode.selectBy(col=value))
64
+ assert len(rows) == 1
65
+ if PY2:
66
+ rows = list(SOTestUnicode.selectBy(col=value))
67
+ assert len(rows) == 1
68
+ row = SOTestUnicode.byCol(value)
69
+ assert row.so_count == i
70
+
71
+ # starts/endswith/contains
72
+ rows = list(SOTestUnicode.select(SOTestUnicode.q.col.startswith("test")))
73
+ assert len(rows) == 1
74
+ rows = list(SOTestUnicode.select(SOTestUnicode.q.col.endswith("test")))
75
+ assert len(rows) == 2
76
+ rows = list(SOTestUnicode.select(SOTestUnicode.q.col.contains("test")))
77
+ assert len(rows) == 2
78
+ rows = list(SOTestUnicode.select(
79
+ SOTestUnicode.q.col.startswith(u"\u00f0")))
80
+ assert len(rows) == 1
81
+ rows = list(SOTestUnicode.select(SOTestUnicode.q.col.endswith(u"\u00f0")))
82
+ assert len(rows) == 1
83
+ rows = list(SOTestUnicode.select(SOTestUnicode.q.col.contains(u"\u00f0")))
84
+ assert len(rows) == 1
@@ -0,0 +1,40 @@
1
+ from uuid import UUID
2
+ from sqlobject import SQLObject, UuidCol
3
+ from sqlobject.tests.dbtest import setupClass
4
+
5
+
6
+ ########################################
7
+ # Uuid columns
8
+ ########################################
9
+
10
+
11
+ testuuid = UUID('7e3b5c1e-3402-4b10-a3c6-8ee6dbac7d1a')
12
+
13
+
14
+ class UuidContainer(SQLObject):
15
+ uuiddata = UuidCol(alternateID=True, default=None)
16
+
17
+
18
+ def test_uuidCol():
19
+ setupClass([UuidContainer])
20
+
21
+ my_uuid = UuidContainer(uuiddata=testuuid)
22
+ iid = my_uuid.id
23
+
24
+ UuidContainer._connection.cache.clear()
25
+
26
+ my_uuid_2 = UuidContainer.get(iid)
27
+
28
+ assert my_uuid_2.uuiddata == testuuid
29
+
30
+
31
+ def test_alternate_id():
32
+ setupClass([UuidContainer])
33
+
34
+ UuidContainer(uuiddata=testuuid)
35
+
36
+ UuidContainer._connection.cache.clear()
37
+
38
+ my_uuid_2 = UuidContainer.byUuiddata(testuuid)
39
+
40
+ assert my_uuid_2.uuiddata == testuuid
@@ -0,0 +1,125 @@
1
+ from sqlobject import BoolCol, FloatCol, IntCol, PickleCol, SQLObject, \
2
+ StringCol, UnicodeCol
3
+ from sqlobject.col import validators
4
+ from sqlobject.compat import PY2
5
+ from sqlobject.tests.dbtest import raises, setupClass
6
+
7
+ if not PY2:
8
+ # alias for python 3 compatability
9
+ long = int
10
+
11
+ ########################################
12
+ # Validation/conversion
13
+ ########################################
14
+
15
+
16
+ class SOTestValidator(validators.Validator):
17
+ def to_python(self, value, state):
18
+ if value:
19
+ self.save_value.append(value)
20
+ return 1
21
+ return value
22
+
23
+ def from_python(self, value, state):
24
+ if value:
25
+ self.save_value.append(value)
26
+ return 2
27
+ return value
28
+
29
+ validator1 = SOTestValidator(save_value=[])
30
+ validator2 = SOTestValidator(save_value=[])
31
+
32
+
33
+ class SOValidation(SQLObject):
34
+
35
+ name = StringCol(validator=validators.PlainText(),
36
+ default='x', dbName='name_col')
37
+ name2 = StringCol(validator2=validators.ConfirmType(type=str), default='y')
38
+ name3 = IntCol(validator=validators.Wrapper(fromPython=int), default=100)
39
+ name4 = FloatCol(default=2.718)
40
+ name5 = PickleCol(default=None)
41
+ name6 = BoolCol(default=None)
42
+ name7 = UnicodeCol(default=None)
43
+ name8 = IntCol(default=None)
44
+ name9 = IntCol(validator=validator1, validator2=validator2, default=0)
45
+
46
+
47
+ class SOValidationTest(object):
48
+ def __init__(self, value):
49
+ self.value = value
50
+
51
+
52
+ if PY2:
53
+ class SOValidationTestUnicode(SOValidationTest):
54
+ def __unicode__(self):
55
+ return self.value
56
+
57
+
58
+ class SOValidationTestInt(SOValidationTest):
59
+ def __int__(self):
60
+ return self.value
61
+
62
+
63
+ class SOValidationTestBool(SOValidationTest):
64
+ def __nonzero__(self):
65
+ return self.value
66
+ __bool__ = __nonzero__
67
+
68
+
69
+ class SOValidationTestFloat(SOValidationTest):
70
+ def __float__(self):
71
+ return self.value
72
+
73
+
74
+ class TestValidation:
75
+
76
+ def setup_method(self, meth):
77
+ setupClass(SOValidation)
78
+
79
+ def test_validate(self):
80
+ t = SOValidation(name='hey')
81
+ raises(validators.Invalid, setattr, t, 'name', '!!!')
82
+ t.name = 'you'
83
+ assert t.name == 'you'
84
+
85
+ def test_confirmType(self):
86
+ t = SOValidation(name2='hey')
87
+ raises(validators.Invalid, setattr, t, 'name2', 1)
88
+ raises(validators.Invalid, setattr, t, 'name3', '1')
89
+ raises(validators.Invalid, setattr, t, 'name4', '1')
90
+ if t._connection.dbName != 'postgres' or \
91
+ t._connection.driver not in ('odbc', 'pyodbc', 'pypyodbc'):
92
+ raises(validators.Invalid, setattr, t, 'name6', '1')
93
+ raises(validators.Invalid, setattr, t, 'name7', 1)
94
+ t.name2 = 'you'
95
+ assert t.name2 == 'you'
96
+
97
+ for name, cls, value in (
98
+ ('name4', SOValidationTestFloat, 1.1),
99
+ ('name6', SOValidationTestBool, True),
100
+ ('name8', SOValidationTestInt, 1)):
101
+ setattr(t, name, cls(value))
102
+ assert getattr(t, name) == value
103
+ if PY2:
104
+ for name, cls, value in (
105
+ ('name7', SOValidationTestUnicode, u'test'),):
106
+ setattr(t, name, cls(value))
107
+ assert getattr(t, name) == value
108
+
109
+ def test_wrapType(self):
110
+ t = SOValidation(name3=1)
111
+ raises(validators.Invalid, setattr, t, 'name3', 'x')
112
+ t.name3 = long(1)
113
+ assert t.name3 == 1
114
+ t.name3 = 0
115
+ assert t.name3 == 0
116
+
117
+ def test_emptyValue(self):
118
+ t = SOValidation(name5={})
119
+ assert t.name5 == {}
120
+
121
+ def test_validator2(self):
122
+ SOValidation(name9=1)
123
+ SOValidation(name9=2)
124
+ assert validator1.save_value == [2, 2, 2, 2, 2, 2]
125
+ assert validator2.save_value == [1, 1, 1, 2, 1, 1]
@@ -0,0 +1,159 @@
1
+ from sqlobject import ForeignKey, IntCol, SQLMultipleJoin, SQLObject, \
2
+ StringCol, func
3
+ from sqlobject.views import ViewSQLObject
4
+ from sqlobject.tests.dbtest import inserts, setupClass
5
+
6
+
7
+ class PhoneNumber(SQLObject):
8
+ number = StringCol()
9
+ calls = SQLMultipleJoin('PhoneCall')
10
+ incoming = SQLMultipleJoin('PhoneCall', joinColumn='toID')
11
+
12
+
13
+ class PhoneCall(SQLObject):
14
+ phoneNumber = ForeignKey('PhoneNumber')
15
+ to = ForeignKey('PhoneNumber')
16
+ minutes = IntCol()
17
+
18
+
19
+ class ViewPhoneCall(ViewSQLObject):
20
+ class sqlmeta:
21
+ idName = PhoneCall.q.id
22
+ clause = PhoneCall.q.phoneNumberID == PhoneNumber.q.id
23
+
24
+ minutes = IntCol(dbName=PhoneCall.q.minutes)
25
+ number = StringCol(dbName=PhoneNumber.q.number)
26
+ phoneNumber = ForeignKey('PhoneNumber', dbName=PhoneNumber.q.id)
27
+ call = ForeignKey('PhoneCall', dbName=PhoneCall.q.id)
28
+
29
+
30
+ class ViewPhone(ViewSQLObject):
31
+ class sqlmeta:
32
+ idName = PhoneNumber.q.id
33
+ clause = PhoneCall.q.phoneNumberID == PhoneNumber.q.id
34
+
35
+ minutes = IntCol(dbName=func.SUM(PhoneCall.q.minutes))
36
+ numberOfCalls = IntCol(dbName=func.COUNT(PhoneCall.q.phoneNumberID))
37
+ number = StringCol(dbName=PhoneNumber.q.number)
38
+ phoneNumber = ForeignKey('PhoneNumber', dbName=PhoneNumber.q.id)
39
+ calls = SQLMultipleJoin('PhoneCall', joinColumn='phoneNumberID')
40
+ vCalls = SQLMultipleJoin('ViewPhoneCall', joinColumn='phoneNumberID',
41
+ orderBy='id')
42
+
43
+
44
+ class ViewPhoneMore(ViewSQLObject):
45
+ ''' View on top of view '''
46
+ class sqlmeta:
47
+ idName = ViewPhone.q.id
48
+ clause = ViewPhone.q.id == PhoneCall.q.toID
49
+
50
+ number = StringCol(dbName=ViewPhone.q.number)
51
+ timesCalled = IntCol(dbName=func.COUNT(PhoneCall.q.toID))
52
+ timesCalledLong = IntCol(dbName=func.COUNT(PhoneCall.q.toID))
53
+ timesCalledLong.aggregateClause = PhoneCall.q.minutes > 10
54
+ minutesCalled = IntCol(dbName=func.SUM(PhoneCall.q.minutes))
55
+
56
+
57
+ class ViewPhoneMore2(ViewPhoneMore):
58
+ class sqlmeta:
59
+ table = 'vpm'
60
+
61
+
62
+ class ViewPhoneInnerAggregate(ViewPhone):
63
+ twiceMinutes = IntCol(dbName=func.SUM(PhoneCall.q.minutes) * 2)
64
+
65
+
66
+ def setup_module(mod):
67
+ global calls, phones, sqlrepr
68
+ setupClass([PhoneNumber, PhoneCall])
69
+ ViewPhoneCall._connection = PhoneNumber._connection
70
+ ViewPhone._connection = PhoneNumber._connection
71
+ ViewPhoneMore._connection = PhoneNumber._connection
72
+ phones = inserts(PhoneNumber, [('1234567890',), ('1111111111',)], 'number')
73
+ calls = inserts(PhoneCall, [(phones[0], phones[1], 5),
74
+ (phones[0], phones[1], 20),
75
+ (phones[1], phones[0], 10),
76
+ (phones[1], phones[0], 25)],
77
+ 'phoneNumber to minutes')
78
+ sqlrepr = PhoneNumber._connection.sqlrepr
79
+
80
+
81
+ def testSimpleVPC():
82
+ assert hasattr(ViewPhoneCall, 'minutes')
83
+ assert hasattr(ViewPhoneCall, 'number')
84
+ assert hasattr(ViewPhoneCall, 'phoneNumberID')
85
+
86
+
87
+ def testColumnSQLVPC():
88
+ assert str(sqlrepr(ViewPhoneCall.q.id)) == 'view_phone_call.id'
89
+ assert str(sqlrepr(ViewPhoneCall.q.minutes)) == 'view_phone_call.minutes'
90
+ q = sqlrepr(ViewPhoneCall.q)
91
+ assert q.count('phone_call.minutes AS minutes')
92
+ assert q.count('phone_number.number AS number')
93
+
94
+
95
+ def testAliasOverride():
96
+ assert str(sqlrepr(ViewPhoneMore2.q.id)) == 'vpm.id'
97
+
98
+
99
+ def checkAttr(cls, id, attr, value):
100
+ assert getattr(cls.get(id), attr) == value
101
+
102
+
103
+ def testGetVPC():
104
+ checkAttr(ViewPhoneCall, calls[0].id, 'number',
105
+ calls[0].phoneNumber.number)
106
+ checkAttr(ViewPhoneCall, calls[0].id, 'minutes', calls[0].minutes)
107
+ checkAttr(ViewPhoneCall, calls[0].id, 'phoneNumber', calls[0].phoneNumber)
108
+ checkAttr(ViewPhoneCall, calls[2].id, 'number',
109
+ calls[2].phoneNumber.number)
110
+ checkAttr(ViewPhoneCall, calls[2].id, 'minutes', calls[2].minutes)
111
+ checkAttr(ViewPhoneCall, calls[2].id, 'phoneNumber', calls[2].phoneNumber)
112
+
113
+
114
+ def testGetVP():
115
+ checkAttr(ViewPhone, phones[0].id, 'number', phones[0].number)
116
+ checkAttr(ViewPhone, phones[0].id, 'minutes',
117
+ phones[0].calls.sum(PhoneCall.q.minutes))
118
+ checkAttr(ViewPhone, phones[0].id, 'phoneNumber', phones[0])
119
+
120
+
121
+ def testGetVPM():
122
+ checkAttr(ViewPhoneMore, phones[0].id, 'number', phones[0].number)
123
+ checkAttr(ViewPhoneMore, phones[0].id, 'minutesCalled',
124
+ phones[0].incoming.sum(PhoneCall.q.minutes))
125
+ checkAttr(ViewPhoneMore, phones[0].id, 'timesCalled',
126
+ phones[0].incoming.count())
127
+ checkAttr(ViewPhoneMore, phones[0].id, 'timesCalledLong',
128
+ phones[0].incoming.filter(PhoneCall.q.minutes > 10).count())
129
+
130
+
131
+ def testJoinView():
132
+ p = ViewPhone.get(phones[0].id)
133
+ assert p.calls.count() == 2
134
+ assert p.vCalls.count() == 2
135
+ assert p.vCalls[0] == ViewPhoneCall.get(calls[0].id)
136
+
137
+
138
+ def testInnerAggregate():
139
+ checkAttr(ViewPhoneInnerAggregate, phones[0].id, 'twiceMinutes',
140
+ phones[0].calls.sum(PhoneCall.q.minutes) * 2)
141
+
142
+
143
+ def testSelect():
144
+ s = ViewPhone.select()
145
+ assert s.count() == len(phones)
146
+ s = ViewPhoneCall.select()
147
+ assert s.count() == len(calls)
148
+
149
+
150
+ def testSelect2():
151
+ s = ViewPhone.select(ViewPhone.q.number == phones[0].number)
152
+ assert s.getOne().phoneNumber == phones[0]
153
+
154
+
155
+ def testDistinctCount():
156
+ # This test is for SelectResults non-* based count when distinct
157
+ # We're really just checking this doesn't raise anything
158
+ # due to lack of sqlrepr'ing.
159
+ assert ViewPhone.select(distinct=True).count() == 2
@@ -0,0 +1 @@
1
+ #