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,120 @@
1
+ from datetime import datetime
2
+ from sqlobject import col, events, SQLObject, AND
3
+
4
+
5
+ class Version(SQLObject):
6
+ def restore(self):
7
+ values = self.sqlmeta.asDict()
8
+ del values['id']
9
+ del values['masterID']
10
+ del values['dateArchived']
11
+ for _col in self.extraCols:
12
+ del values[_col]
13
+ self.masterClass.get(self.masterID).set(**values)
14
+
15
+ def nextVersion(self):
16
+ version = self.select(
17
+ AND(self.q.masterID == self.masterID, self.q.id > self.id),
18
+ orderBy=self.q.id)
19
+ if version.count():
20
+ return version[0]
21
+ else:
22
+ return self.master
23
+
24
+ def getChangedFields(self):
25
+ next = self.nextVersion()
26
+ columns = self.masterClass.sqlmeta.columns
27
+ fields = []
28
+ for column in columns:
29
+ if column not in ["dateArchived", "id", "masterID"]:
30
+ if getattr(self, column) != getattr(next, column):
31
+ fields.append(column.title())
32
+
33
+ return fields
34
+
35
+ @classmethod
36
+ def select(cls, clause=None, *args, **kw):
37
+ if not getattr(cls, '_connection', None):
38
+ cls._connection = cls.masterClass._connection
39
+ return super(Version, cls).select(clause, *args, **kw)
40
+
41
+ def __getattr__(self, attr):
42
+ if attr in self.__dict__:
43
+ return self.__dict__[attr]
44
+ else:
45
+ return getattr(self.master, attr)
46
+
47
+
48
+ def getColumns(columns, cls):
49
+ for column, defi in cls.sqlmeta.columnDefinitions.items():
50
+ if column.endswith("ID") and isinstance(defi, col.ForeignKey):
51
+ column = column[:-2]
52
+
53
+ # remove incompatible constraints
54
+ kwds = dict(defi._kw)
55
+ for kw in ["alternateID", "unique"]:
56
+ if kw in kwds:
57
+ del kwds[kw]
58
+ columns[column] = defi.__class__(**kwds)
59
+
60
+ # ascend heirarchy
61
+ if cls.sqlmeta.parentClass:
62
+ getColumns(columns, cls.sqlmeta.parentClass)
63
+
64
+
65
+ class Versioning(object):
66
+ def __init__(self, extraCols=None):
67
+ if extraCols:
68
+ self.extraCols = extraCols
69
+ else:
70
+ self.extraCols = {}
71
+ pass
72
+
73
+ def __addtoclass__(self, soClass, name):
74
+ self.name = name
75
+ self.soClass = soClass
76
+
77
+ attrs = {'dateArchived': col.DateTimeCol(default=datetime.now),
78
+ 'master': col.ForeignKey(self.soClass.__name__),
79
+ 'masterClass': self.soClass,
80
+ 'extraCols': self.extraCols
81
+ }
82
+
83
+ getColumns(attrs, self.soClass)
84
+
85
+ attrs.update(self.extraCols)
86
+
87
+ self.versionClass = type(self.soClass.__name__ + 'Versions',
88
+ (Version,),
89
+ attrs)
90
+
91
+ if '_connection' in self.soClass.__dict__:
92
+ self.versionClass._connection = \
93
+ self.soClass.__dict__['_connection']
94
+
95
+ events.listen(self.createTable,
96
+ soClass, events.CreateTableSignal)
97
+ events.listen(self.rowUpdate, soClass,
98
+ events.RowUpdateSignal)
99
+
100
+ def createVersionTable(self, cls, conn):
101
+ self.versionClass.createTable(ifNotExists=True, connection=conn)
102
+
103
+ def createTable(self, soClass, connection, extra_sql, post_funcs):
104
+ assert soClass is self.soClass
105
+ post_funcs.append(self.createVersionTable)
106
+
107
+ def rowUpdate(self, instance, kwargs):
108
+ if instance.childName and instance.childName != self.soClass.__name__:
109
+ return # if you want your child class versioned, version it
110
+
111
+ values = instance.sqlmeta.asDict()
112
+ del values['id']
113
+ values['masterID'] = instance.id
114
+ self.versionClass(connection=instance._connection, **values)
115
+
116
+ def __get__(self, obj, type=None):
117
+ if obj is None:
118
+ return self
119
+ return self.versionClass.select(
120
+ self.versionClass.q.masterID == obj.id, connection=obj._connection)
File without changes
@@ -0,0 +1,183 @@
1
+ from sqlobject import ForeignKey, IntCol, SQLObject, StringCol
2
+ from sqlobject.inheritance import InheritableSQLObject
3
+ from sqlobject.versioning import Versioning
4
+ from sqlobject.tests.dbtest import setupClass
5
+
6
+
7
+ class MyClass(SQLObject):
8
+ name = StringCol()
9
+ versions = Versioning()
10
+
11
+
12
+ class Base(InheritableSQLObject):
13
+ name = StringCol()
14
+ so_value = IntCol(default=0)
15
+ versions = Versioning()
16
+
17
+
18
+ class Child(Base):
19
+ toy = StringCol()
20
+
21
+
22
+ class Government(InheritableSQLObject):
23
+ name = StringCol()
24
+
25
+
26
+ class Monarchy(Government):
27
+ monarch = StringCol()
28
+ versions = Versioning()
29
+
30
+
31
+ class VChild(Base):
32
+ weapon = StringCol()
33
+ versions = Versioning()
34
+
35
+
36
+ class HasForeign(SQLObject):
37
+ foreign = ForeignKey("Base")
38
+ versions = Versioning()
39
+
40
+
41
+ def _set_extra():
42
+ return "read all about it"
43
+
44
+
45
+ class Extra(SQLObject):
46
+ name = StringCol()
47
+ versions = Versioning(
48
+ extraCols={'extra': StringCol(default=_set_extra())})
49
+
50
+
51
+ class HasAltId(SQLObject):
52
+ name = StringCol()
53
+ altid = IntCol(alternateID=True)
54
+ versions = Versioning()
55
+
56
+
57
+ def setup():
58
+ classes = [MyClass, Base, Child, Government,
59
+ Monarchy, VChild, Extra, HasAltId]
60
+ if hasattr(HasForeign, "_connection"):
61
+ classes.insert(0, HasForeign)
62
+ else:
63
+ classes.append(HasForeign)
64
+ for cls in classes:
65
+ if hasattr(cls, 'versions') and getattr(cls, "_connection", None) and \
66
+ cls._connection.tableExists(cls.sqlmeta.table):
67
+ setupClass(cls.versions.versionClass)
68
+ setupClass(cls)
69
+ if hasattr(cls, 'versions'):
70
+ setupClass(cls.versions.versionClass)
71
+ for version in cls.versions.versionClass.select():
72
+ version.destroySelf()
73
+
74
+
75
+ def test_versioning():
76
+ # the simple case
77
+ setup()
78
+ mc = MyClass(name='fleem')
79
+ mc.set(name='morx')
80
+ assert len(list(mc.versions)) == 1
81
+ assert mc.versions[0].name == "fleem"
82
+
83
+ assert len(list(MyClass.select())) == 1
84
+
85
+
86
+ def test_inheritable_versioning():
87
+ setup()
88
+
89
+ # base versioned, child unversioned
90
+ base = Base(name='fleem')
91
+ base.set(name='morx')
92
+ assert len(list(base.versions)) == 1
93
+ assert base.versions[0].name == "fleem"
94
+ assert len(list(Base.select())) == 1
95
+
96
+ child = Child(name='child', toy='nintendo')
97
+ child.set(name='teenager', toy='guitar')
98
+ assert len(list(child.versions)) == 0
99
+
100
+ # child versioned, base unversioned
101
+ government = Government(name='canada')
102
+ assert not hasattr(government, 'versions')
103
+
104
+ monarchy = Monarchy(name='UK', monarch='king george iv')
105
+ assert len(list(monarchy.versions)) == 0
106
+ monarchy.set(name='queen elisabeth ii')
107
+ assert len(list(monarchy.versions)) == 1
108
+ assert monarchy.versions[0].name == "UK"
109
+ assert len(list(Monarchy.select())) == 1
110
+
111
+ # both parent and child versioned
112
+ num_base_versions = len(list(base.versions))
113
+ vchild = VChild(name='kid', weapon='slingshot')
114
+ vchild.set(name='toon', weapon='dynamite')
115
+ assert len(list(base.versions)) == num_base_versions
116
+ assert len(list(vchild.versions)) == 1
117
+ # test setting using setattr directly rather than .set
118
+ vchild.name = "newname"
119
+ assert len(list(vchild.versions)) == 2
120
+
121
+
122
+ def test_restore():
123
+ setup()
124
+ base = Base(name='fleem')
125
+ base.set(name='morx')
126
+ assert base.name == "morx"
127
+ base.versions[0].restore()
128
+ assert base.name == "fleem"
129
+
130
+ monarchy = Monarchy(name='USA', monarch='Emperor Norton I')
131
+ monarchy.set(name='morx')
132
+ assert monarchy.name == "morx"
133
+ monarchy.versions[0].restore()
134
+ assert monarchy.name == "USA"
135
+ assert monarchy.monarch == "Emperor Norton I"
136
+
137
+ extra = Extra(name='fleem')
138
+ extra.set(name='morx')
139
+ assert extra.name == "morx"
140
+ extra.versions[0].restore()
141
+ assert extra.name == "fleem"
142
+
143
+
144
+ def test_next():
145
+ setup()
146
+ base = Base(name='first', so_value=1)
147
+ base.set(name='second')
148
+ base.set(name='third', so_value=2)
149
+ version = base.versions[0]
150
+ assert version.nextVersion() == base.versions[1]
151
+ assert version.nextVersion().nextVersion() == base
152
+
153
+
154
+ def test_get_changed():
155
+ setup()
156
+ base = Base(name='first', so_value=1)
157
+ base.set(name='second')
158
+ base.set(name='third', so_value=2)
159
+ assert base.versions[0].getChangedFields() == ['Name']
160
+ assert sorted(base.versions[1].getChangedFields()) == ['Name', 'So_Value']
161
+
162
+
163
+ def test_foreign_keys():
164
+ setup()
165
+ base1 = Base(name='first', so_value=1)
166
+ base2 = Base(name='first', so_value=1)
167
+ has_foreign = HasForeign(foreign=base1)
168
+ has_foreign.foreign = base2
169
+ assert has_foreign.versions[0].foreign == base1
170
+
171
+
172
+ def test_extra():
173
+ setup()
174
+ extra = Extra(name='title')
175
+ extra.name = 'new'
176
+ assert extra.versions[0].extra == 'read all about it'
177
+ assert sorted(extra.versions[0].getChangedFields()) == ['Name']
178
+
179
+
180
+ def test_altid():
181
+ setup()
182
+ extra = HasAltId(name="fleem", altid=5)
183
+ extra.name = "morx"
sqlobject/views.py ADDED
@@ -0,0 +1,151 @@
1
+ from .main import SQLObject
2
+ from .sqlbuilder import AND, Alias, ColumnAS, LEFTJOINOn, \
3
+ NoDefault, SQLCall, SQLConstant, SQLObjectField, SQLObjectTable, SQLOp, \
4
+ Select, sqlrepr
5
+
6
+
7
+ class ViewSQLObjectField(SQLObjectField):
8
+ def __init__(self, alias, *arg):
9
+ SQLObjectField.__init__(self, *arg)
10
+ self.alias = alias
11
+
12
+ def __sqlrepr__(self, db):
13
+ return self.alias + "." + self.fieldName
14
+
15
+ def tablesUsedImmediate(self):
16
+ return [self.tableName]
17
+
18
+
19
+ class ViewSQLObjectTable(SQLObjectTable):
20
+ FieldClass = ViewSQLObjectField
21
+
22
+ def __getattr__(self, attr):
23
+ if attr == 'sqlmeta':
24
+ raise AttributeError
25
+ return SQLObjectTable.__getattr__(self, attr)
26
+
27
+ def _getattrFromID(self, attr):
28
+ return self.FieldClass(self.soClass.sqlmeta.alias, self.tableName,
29
+ 'id', attr, self.soClass, None)
30
+
31
+ def _getattrFromColumn(self, column, attr):
32
+ return self.FieldClass(self.soClass.sqlmeta.alias, self.tableName,
33
+ column.name, attr, self.soClass, column)
34
+
35
+
36
+ class ViewSQLObject(SQLObject):
37
+ """
38
+ A SQLObject class that derives all it's values from other SQLObject
39
+ classes. Columns on subclasses should use SQLBuilder constructs for dbName,
40
+ and sqlmeta should specify:
41
+
42
+ * idName as a SQLBuilder construction
43
+ * clause as SQLBuilder clause for specifying join conditions
44
+ or other restrictions
45
+ * table as an optional alternate name for the class alias
46
+
47
+ See test_views.py for simple examples.
48
+ """
49
+
50
+ def __classinit__(cls, new_attrs):
51
+ SQLObject.__classinit__(cls, new_attrs)
52
+ # like is_base
53
+ if cls.__name__ != 'ViewSQLObject':
54
+ dbName = hasattr(cls, '_connection') and \
55
+ (cls._connection and cls._connection.dbName) or None
56
+
57
+ if getattr(cls.sqlmeta, 'table', None):
58
+ cls.sqlmeta.alias = cls.sqlmeta.table
59
+ else:
60
+ cls.sqlmeta.alias = \
61
+ cls.sqlmeta.style.pythonClassToDBTable(cls.__name__)
62
+ alias = cls.sqlmeta.alias
63
+ columns = [ColumnAS(cls.sqlmeta.idName, 'id')]
64
+ # {sqlrepr-key: [restriction, *aggregate-column]}
65
+ aggregates = {'': [None]}
66
+ inverseColumns = dict(
67
+ [(y, x) for x, y in cls.sqlmeta.columns.items()])
68
+ for col in cls.sqlmeta.columnList:
69
+ n = inverseColumns[col]
70
+ ascol = ColumnAS(col.dbName, n)
71
+ if isAggregate(col.dbName):
72
+ restriction = getattr(col, 'aggregateClause', None)
73
+ if restriction:
74
+ restrictkey = sqlrepr(restriction, dbName)
75
+ aggregates[restrictkey] = \
76
+ aggregates.get(restrictkey, [restriction]) + \
77
+ [ascol]
78
+ else:
79
+ aggregates[''].append(ascol)
80
+ else:
81
+ columns.append(ascol)
82
+
83
+ metajoin = getattr(cls.sqlmeta, 'join', NoDefault)
84
+ clause = getattr(cls.sqlmeta, 'clause', NoDefault)
85
+ select = Select(columns,
86
+ distinct=True,
87
+ # @@ LDO check if this really mattered
88
+ # for performance
89
+ # @@ Postgres (and MySQL?) extension!
90
+ # distinctOn=cls.sqlmeta.idName,
91
+ join=metajoin,
92
+ clause=clause)
93
+
94
+ aggregates = aggregates.values()
95
+
96
+ if aggregates != [[None]]:
97
+ join = []
98
+ last_alias = "%s_base" % alias
99
+ last_id = "id"
100
+ last = Alias(select, last_alias)
101
+ columns = [
102
+ ColumnAS(SQLConstant("%s.%s" % (last_alias, x.expr2)),
103
+ x.expr2) for x in columns]
104
+
105
+ for i, agg in enumerate(aggregates):
106
+ restriction = agg[0]
107
+ if restriction is None:
108
+ restriction = clause
109
+ else:
110
+ restriction = AND(clause, restriction)
111
+ agg = agg[1:]
112
+ agg_alias = "%s_%s" % (alias, i)
113
+ agg_id = '%s_id' % agg_alias
114
+ if not last.q.alias.endswith('base'):
115
+ last = None
116
+ new_alias = Alias(Select(
117
+ [ColumnAS(cls.sqlmeta.idName, agg_id)] + agg,
118
+ groupBy=cls.sqlmeta.idName,
119
+ join=metajoin,
120
+ clause=restriction),
121
+ agg_alias)
122
+ agg_join = LEFTJOINOn(last, new_alias,
123
+ "%s.%s = %s.%s" % (
124
+ last_alias, last_id,
125
+ agg_alias, agg_id))
126
+
127
+ join.append(agg_join)
128
+ for col in agg:
129
+ columns.append(
130
+ ColumnAS(SQLConstant(
131
+ "%s.%s" % (agg_alias, col.expr2)),
132
+ col.expr2))
133
+
134
+ last = new_alias
135
+ last_alias = agg_alias
136
+ last_id = agg_id
137
+ select = Select(columns,
138
+ join=join)
139
+
140
+ cls.sqlmeta.table = Alias(select, alias)
141
+ cls.q = ViewSQLObjectTable(cls)
142
+ for n, col in cls.sqlmeta.columns.items():
143
+ col.dbName = n
144
+
145
+
146
+ def isAggregate(expr):
147
+ if isinstance(expr, SQLCall):
148
+ return True
149
+ if isinstance(expr, SQLOp):
150
+ return isAggregate(expr.expr1) or isAggregate(expr.expr2)
151
+ return False
@@ -0,0 +1,109 @@
1
+ import sys
2
+ import sqlobject
3
+ from sqlobject.compat import string_type
4
+
5
+ # The module was imported during documentation building
6
+ if 'sphinx' not in sys.modules:
7
+ from paste.deploy.converters import asbool
8
+ from paste.wsgilib import catch_errors
9
+ from paste.util import import_string
10
+
11
+
12
+ def make_middleware(app, global_conf, database=None, use_transaction=False,
13
+ hub=None):
14
+ """
15
+ WSGI middleware that sets the connection for the request (using
16
+ the database URI or connection object) and the given hub (or
17
+ ``sqlobject.sqlhub`` if not given).
18
+
19
+ If ``use_transaction`` is true, then the request will be run in a
20
+ transaction.
21
+
22
+ Applications can use the keys (which are all no-argument functions):
23
+
24
+ ``sqlobject.get_connection()``:
25
+ Returns the connection object
26
+
27
+ ``sqlobject.abort()``:
28
+ Aborts the transaction. Does not raise an error, but at the *end*
29
+ of the request there will be a rollback.
30
+
31
+ ``sqlobject.begin()``:
32
+ Starts a transaction. First commits (or rolls back if aborted) if
33
+ this is run in a transaction.
34
+
35
+ ``sqlobject.in_transaction()``:
36
+ Returns true or false, depending if we are currently in a
37
+ transaction.
38
+ """
39
+ use_transaction = asbool(use_transaction)
40
+ if database is None:
41
+ database = global_conf.get('database')
42
+ if not database:
43
+ raise ValueError(
44
+ "You must provide a 'database' configuration value")
45
+ if isinstance(hub, string_type):
46
+ hub = import_string.eval_import(hub)
47
+ if not hub:
48
+ hub = sqlobject.sqlhub
49
+ if isinstance(database, string_type):
50
+ database = sqlobject.connectionForURI(database)
51
+ return SQLObjectMiddleware(app, database, use_transaction, hub)
52
+
53
+
54
+ class SQLObjectMiddleware(object):
55
+
56
+ def __init__(self, app, conn, use_transaction, hub):
57
+ self.app = app
58
+ self.conn = conn
59
+ self.use_transaction = use_transaction
60
+ self.hub = hub
61
+
62
+ def __call__(self, environ, start_response):
63
+ conn = [self.conn]
64
+ if self.use_transaction:
65
+ conn[0] = conn[0].transaction()
66
+ any_errors = []
67
+ use_transaction = [self.use_transaction]
68
+ self.hub.threadConnection = conn[0]
69
+
70
+ def abort():
71
+ assert use_transaction[0], (
72
+ "You cannot abort, because a transaction is not being used")
73
+ any_errors.append(None)
74
+
75
+ def begin():
76
+ if use_transaction[0]:
77
+ if any_errors:
78
+ conn[0].rollback()
79
+ else:
80
+ conn[0].commit()
81
+ any_errors[:] = []
82
+ use_transaction[0] = True
83
+ conn[0] = self.conn.transaction()
84
+ self.hub.threadConnection = conn[0]
85
+
86
+ def error(exc_info=None):
87
+ any_errors.append(None)
88
+ ok()
89
+
90
+ def ok():
91
+ if use_transaction[0]:
92
+ if any_errors:
93
+ conn[0].rollback()
94
+ else:
95
+ conn[0].commit(close=True)
96
+ self.hub.threadConnection = None
97
+
98
+ def in_transaction():
99
+ return use_transaction[0]
100
+
101
+ def get_connection():
102
+ return conn[0]
103
+
104
+ environ['sqlobject.get_connection'] = get_connection
105
+ environ['sqlobject.abort'] = abort
106
+ environ['sqlobject.begin'] = begin
107
+ environ['sqlobject.in_transaction'] = in_transaction
108
+ return catch_errors(self.app, environ, start_response,
109
+ error_callback=error, ok_callback=ok)
@@ -0,0 +1,36 @@
1
+ #!/usr/bin/env python
2
+ from __future__ import print_function
3
+ import sys
4
+ import os
5
+
6
+ try:
7
+ import pkg_resources
8
+ pkg_resources.require('SQLObject>0.6.1')
9
+ except (ImportError, pkg_resources.DistributionNotFound):
10
+ # Oh well, we tried...
11
+ pass
12
+
13
+ try:
14
+ import sqlobject.manager
15
+ except ImportError:
16
+ try:
17
+ here = __file__
18
+ except NameError:
19
+ here = sys.argv[0]
20
+ updir = os.path.join(
21
+ os.path.dirname(os.path.dirname(os.path.abspath(here))),
22
+ 'sqlobject')
23
+ if os.path.exists(updir):
24
+ sys.path.insert(0, os.path.dirname(updir))
25
+ else:
26
+ print('I cannot find the sqlobject module')
27
+ print('If SQLObject is installed, you may need to set $PYTHONPATH')
28
+ sys.exit(3)
29
+ # Now we have to get rid of possibly stale modules from that import
30
+ # up there
31
+ for name, value in sys.modules.items():
32
+ if name.startswith('sqlobject'):
33
+ del sys.modules[name]
34
+
35
+ from sqlobject.manager import command
36
+ command.the_runner.run(sys.argv)
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env python
2
+ from __future__ import print_function
3
+
4
+ import sys
5
+
6
+ try:
7
+ uri = sys.argv[1]
8
+ except IndexError:
9
+ sys.exit("Usage: %s old-style-URI" % sys.argv[0])
10
+
11
+ try:
12
+ import pkg_resources
13
+ pkg_resources.require('SQLObject>=1.0.0')
14
+ except (ImportError, pkg_resources.DistributionNotFound):
15
+ pass
16
+
17
+ from sqlobject import connectionForURI
18
+ conn = connectionForURI(uri, oldUri=True)
19
+ print(conn.uri())