PageRenderTime 85ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 1ms

/tests/store/base.py

https://github.com/quodt/storm
Python | 6163 lines | 6028 code | 81 blank | 54 comment | 12 complexity | 7aaf102afe85e3b7417bd8e4385980cb MD5 | raw file
Possible License(s): LGPL-2.1
  1. # -*- coding: utf-8 -*-
  2. #
  3. # Copyright (c) 2006, 2007 Canonical
  4. #
  5. # Written by Gustavo Niemeyer <gustavo@niemeyer.net>
  6. #
  7. # This file is part of Storm Object Relational Mapper.
  8. #
  9. # Storm is free software; you can redistribute it and/or modify
  10. # it under the terms of the GNU Lesser General Public License as
  11. # published by the Free Software Foundation; either version 2.1 of
  12. # the License, or (at your option) any later version.
  13. #
  14. # Storm is distributed in the hope that it will be useful,
  15. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. # GNU Lesser General Public License for more details.
  18. #
  19. # You should have received a copy of the GNU Lesser General Public License
  20. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  21. #
  22. from cStringIO import StringIO
  23. import decimal
  24. import gc
  25. import operator
  26. import weakref
  27. from storm.references import Reference, ReferenceSet, Proxy
  28. from storm.database import Result
  29. from storm.properties import Int, Float, RawStr, Unicode, Property, Pickle
  30. from storm.properties import PropertyPublisherMeta, Decimal
  31. from storm.variables import PickleVariable
  32. from storm.expr import (
  33. Asc, Desc, Select, LeftJoin, SQL, Count, Sum, Avg, And, Or, Eq, Lower, Alias)
  34. from storm.variables import Variable, UnicodeVariable, IntVariable
  35. from storm.info import get_obj_info, ClassAlias
  36. from storm.exceptions import (
  37. ClosedError, ConnectionBlockedError, FeatureError, LostObjectError,
  38. NoStoreError, NotFlushedError, NotOneError, OrderLoopError, UnorderedError,
  39. WrongStoreError)
  40. from storm.cache import Cache
  41. from storm.store import AutoReload, EmptyResultSet, Store, ResultSet
  42. from storm.tracer import debug
  43. from tests.info import Wrapper
  44. from tests.helper import TestHelper
  45. class Foo(object):
  46. __storm_table__ = "foo"
  47. id = Int(primary=True)
  48. title = Unicode()
  49. class Bar(object):
  50. __storm_table__ = "bar"
  51. id = Int(primary=True)
  52. title = Unicode()
  53. foo_id = Int()
  54. foo = Reference(foo_id, Foo.id)
  55. class Blob(object):
  56. __storm_table__ = "bin"
  57. id = Int(primary=True)
  58. bin = RawStr()
  59. class Link(object):
  60. __storm_table__ = "link"
  61. __storm_primary__ = "foo_id", "bar_id"
  62. foo_id = Int()
  63. bar_id = Int()
  64. class SelfRef(object):
  65. __storm_table__ = "selfref"
  66. id = Int(primary=True)
  67. title = Unicode()
  68. selfref_id = Int()
  69. selfref = Reference(selfref_id, id)
  70. selfref_on_remote = Reference(id, selfref_id, on_remote=True)
  71. class FooRef(Foo):
  72. bar = Reference(Foo.id, Bar.foo_id)
  73. class FooRefSet(Foo):
  74. bars = ReferenceSet(Foo.id, Bar.foo_id)
  75. class FooRefSetOrderID(Foo):
  76. bars = ReferenceSet(Foo.id, Bar.foo_id, order_by=Bar.id)
  77. class FooRefSetOrderTitle(Foo):
  78. bars = ReferenceSet(Foo.id, Bar.foo_id, order_by=Bar.title)
  79. class FooIndRefSet(Foo):
  80. bars = ReferenceSet(Foo.id, Link.foo_id, Link.bar_id, Bar.id)
  81. class FooIndRefSetOrderID(Foo):
  82. bars = ReferenceSet(Foo.id, Link.foo_id, Link.bar_id, Bar.id,
  83. order_by=Bar.id)
  84. class FooIndRefSetOrderTitle(Foo):
  85. bars = ReferenceSet(Foo.id, Link.foo_id, Link.bar_id, Bar.id,
  86. order_by=Bar.title)
  87. class FooValue(object):
  88. __storm_table__ = "foovalue"
  89. id = Int(primary=True)
  90. foo_id = Int()
  91. value1 = Int()
  92. value2 = Int()
  93. class BarProxy(object):
  94. __storm_table__ = "bar"
  95. id = Int(primary=True)
  96. title = Unicode()
  97. foo_id = Int()
  98. foo = Reference(foo_id, Foo.id)
  99. foo_title = Proxy(foo, Foo.title)
  100. class Money(object):
  101. __storm_table__ = "money"
  102. id = Int(primary=True)
  103. value = Decimal()
  104. class DecorateVariable(Variable):
  105. def parse_get(self, value, to_db):
  106. return u"to_%s(%s)" % (to_db and "db" or "py", value)
  107. def parse_set(self, value, from_db):
  108. return u"from_%s(%s)" % (from_db and "db" or "py", value)
  109. class FooVariable(Foo):
  110. title = Property(variable_class=DecorateVariable)
  111. class DummyDatabase(object):
  112. def connect(self, event=None):
  113. return None
  114. class StoreCacheTest(TestHelper):
  115. def test_wb_custom_cache(self):
  116. cache = Cache(25)
  117. store = Store(DummyDatabase(), cache=cache)
  118. self.assertEquals(store._cache, cache)
  119. def test_wb_default_cache_size(self):
  120. store = Store(DummyDatabase())
  121. self.assertEquals(store._cache._size, 1000)
  122. class StoreDatabaseTest(TestHelper):
  123. def test_store_has_reference_to_its_database(self):
  124. database = DummyDatabase()
  125. store = Store(database)
  126. self.assertIdentical(store.get_database(), database)
  127. class StoreTest(object):
  128. def setUp(self):
  129. self.store = None
  130. self.stores = []
  131. self.create_database()
  132. self.connection = self.database.connect()
  133. self.drop_tables()
  134. self.create_tables()
  135. self.create_sample_data()
  136. self.create_store()
  137. def tearDown(self):
  138. self.drop_store()
  139. self.drop_sample_data()
  140. self.drop_tables()
  141. self.drop_database()
  142. self.connection.close()
  143. def create_database(self):
  144. raise NotImplementedError
  145. def create_tables(self):
  146. raise NotImplementedError
  147. def create_sample_data(self):
  148. connection = self.connection
  149. connection.execute("INSERT INTO foo (id, title)"
  150. " VALUES (10, 'Title 30')")
  151. connection.execute("INSERT INTO foo (id, title)"
  152. " VALUES (20, 'Title 20')")
  153. connection.execute("INSERT INTO foo (id, title)"
  154. " VALUES (30, 'Title 10')")
  155. connection.execute("INSERT INTO bar (id, foo_id, title)"
  156. " VALUES (100, 10, 'Title 300')")
  157. connection.execute("INSERT INTO bar (id, foo_id, title)"
  158. " VALUES (200, 20, 'Title 200')")
  159. connection.execute("INSERT INTO bar (id, foo_id, title)"
  160. " VALUES (300, 30, 'Title 100')")
  161. connection.execute("INSERT INTO bin (id, bin) VALUES (10, 'Blob 30')")
  162. connection.execute("INSERT INTO bin (id, bin) VALUES (20, 'Blob 20')")
  163. connection.execute("INSERT INTO bin (id, bin) VALUES (30, 'Blob 10')")
  164. connection.execute("INSERT INTO link (foo_id, bar_id) VALUES (10, 100)")
  165. connection.execute("INSERT INTO link (foo_id, bar_id) VALUES (10, 200)")
  166. connection.execute("INSERT INTO link (foo_id, bar_id) VALUES (10, 300)")
  167. connection.execute("INSERT INTO link (foo_id, bar_id) VALUES (20, 100)")
  168. connection.execute("INSERT INTO link (foo_id, bar_id) VALUES (20, 200)")
  169. connection.execute("INSERT INTO link (foo_id, bar_id) VALUES (30, 300)")
  170. connection.execute("INSERT INTO money (id, value)"
  171. " VALUES (10, '12.3455')")
  172. connection.execute("INSERT INTO selfref (id, title, selfref_id)"
  173. " VALUES (15, 'SelfRef 15', NULL)")
  174. connection.execute("INSERT INTO selfref (id, title, selfref_id)"
  175. " VALUES (25, 'SelfRef 25', NULL)")
  176. connection.execute("INSERT INTO selfref (id, title, selfref_id)"
  177. " VALUES (35, 'SelfRef 35', 15)")
  178. connection.execute("INSERT INTO foovalue (id, foo_id, value1, value2)"
  179. " VALUES (1, 10, 2, 1)")
  180. connection.execute("INSERT INTO foovalue (id, foo_id, value1, value2)"
  181. " VALUES (2, 10, 2, 1)")
  182. connection.execute("INSERT INTO foovalue (id, foo_id, value1, value2)"
  183. " VALUES (3, 10, 2, 1)")
  184. connection.execute("INSERT INTO foovalue (id, foo_id, value1, value2)"
  185. " VALUES (4, 10, 2, 2)")
  186. connection.execute("INSERT INTO foovalue (id, foo_id, value1, value2)"
  187. " VALUES (5, 20, 1, 3)")
  188. connection.execute("INSERT INTO foovalue (id, foo_id, value1, value2)"
  189. " VALUES (6, 20, 1, 3)")
  190. connection.execute("INSERT INTO foovalue (id, foo_id, value1, value2)"
  191. " VALUES (7, 20, 1, 4)")
  192. connection.execute("INSERT INTO foovalue (id, foo_id, value1, value2)"
  193. " VALUES (8, 20, 1, 4)")
  194. connection.execute("INSERT INTO foovalue (id, foo_id, value1, value2)"
  195. " VALUES (9, 20, 1, 2)")
  196. connection.commit()
  197. def create_store(self):
  198. store = Store(self.database)
  199. self.stores.append(store)
  200. if self.store is None:
  201. self.store = store
  202. return store
  203. def drop_store(self):
  204. for store in self.stores:
  205. store.rollback()
  206. # Closing the store is needed because testcase objects are all
  207. # instantiated at once, and thus connections are kept open.
  208. store.close()
  209. def drop_sample_data(self):
  210. pass
  211. def drop_tables(self):
  212. for table in ["foo", "bar", "bin", "link", "money", "selfref",
  213. "foovalue"]:
  214. try:
  215. self.connection.execute("DROP TABLE %s" % table)
  216. self.connection.commit()
  217. except:
  218. self.connection.rollback()
  219. def drop_database(self):
  220. pass
  221. def get_items(self):
  222. # Bypass the store to avoid flushing.
  223. connection = self.store._connection
  224. result = connection.execute("SELECT * FROM foo ORDER BY id")
  225. return list(result)
  226. def get_committed_items(self):
  227. connection = self.database.connect()
  228. result = connection.execute("SELECT * FROM foo ORDER BY id")
  229. return list(result)
  230. def get_cache(self, store):
  231. # We don't offer a public API for this just yet.
  232. return store._cache
  233. def test_execute(self):
  234. result = self.store.execute("SELECT 1")
  235. self.assertTrue(isinstance(result, Result))
  236. self.assertEquals(result.get_one(), (1,))
  237. result = self.store.execute("SELECT 1", noresult=True)
  238. self.assertEquals(result, None)
  239. def test_execute_params(self):
  240. result = self.store.execute("SELECT ?", [1])
  241. self.assertTrue(isinstance(result, Result))
  242. self.assertEquals(result.get_one(), (1,))
  243. def test_execute_flushes(self):
  244. foo = self.store.get(Foo, 10)
  245. foo.title = u"New Title"
  246. result = self.store.execute("SELECT title FROM foo WHERE id=10")
  247. self.assertEquals(result.get_one(), ("New Title",))
  248. def test_close(self):
  249. store = Store(self.database)
  250. store.close()
  251. self.assertRaises(ClosedError, store.execute, "SELECT 1")
  252. def test_get(self):
  253. foo = self.store.get(Foo, 10)
  254. self.assertEquals(foo.id, 10)
  255. self.assertEquals(foo.title, "Title 30")
  256. foo = self.store.get(Foo, 20)
  257. self.assertEquals(foo.id, 20)
  258. self.assertEquals(foo.title, "Title 20")
  259. foo = self.store.get(Foo, 40)
  260. self.assertEquals(foo, None)
  261. def test_get_cached(self):
  262. foo = self.store.get(Foo, 10)
  263. self.assertTrue(self.store.get(Foo, 10) is foo)
  264. def test_wb_get_cached_doesnt_need_connection(self):
  265. foo = self.store.get(Foo, 10)
  266. connection = self.store._connection
  267. self.store._connection = None
  268. self.store.get(Foo, 10)
  269. self.store._connection = connection
  270. def test_cache_cleanup(self):
  271. # Disable the cache, which holds strong references.
  272. self.get_cache(self.store).set_size(0)
  273. foo = self.store.get(Foo, 10)
  274. foo.taint = True
  275. del foo
  276. gc.collect()
  277. foo = self.store.get(Foo, 10)
  278. self.assertFalse(getattr(foo, "taint", False))
  279. def test_add_returns_object(self):
  280. """
  281. Store.add() returns the object passed to it. This allows this
  282. kind of code:
  283. thing = Thing()
  284. store.add(thing)
  285. return thing
  286. to be simplified as:
  287. return store.add(Thing())
  288. """
  289. foo = Foo()
  290. self.assertEquals(self.store.add(foo), foo)
  291. def test_add_and_stop_referencing(self):
  292. # After adding an object, no references should be needed in
  293. # python for it still to be added to the database.
  294. foo = Foo()
  295. foo.title = u"live"
  296. self.store.add(foo)
  297. del foo
  298. gc.collect()
  299. self.assertTrue(self.store.find(Foo, title=u"live").one())
  300. def test_obj_info_with_deleted_object(self):
  301. # Let's try to put Storm in trouble by killing the object
  302. # while still holding a reference to the obj_info.
  303. # Disable the cache, which holds strong references.
  304. self.get_cache(self.store).set_size(0)
  305. class MyFoo(Foo):
  306. loaded = False
  307. def __storm_loaded__(self):
  308. self.loaded = True
  309. foo = self.store.get(MyFoo, 20)
  310. foo.tainted = True
  311. obj_info = get_obj_info(foo)
  312. del foo
  313. gc.collect()
  314. self.assertEquals(obj_info.get_obj(), None)
  315. foo = self.store.find(MyFoo, id=20).one()
  316. self.assertTrue(foo)
  317. self.assertFalse(getattr(foo, "tainted", False))
  318. # The object was rebuilt, so the loaded hook must have run.
  319. self.assertTrue(foo.loaded)
  320. def test_obj_info_with_deleted_object_and_changed_event(self):
  321. """
  322. When an object is collected, the variables disable change notification
  323. to not create a leak. If we're holding a reference to the obj_info and
  324. rebuild the object, it should re-enable change notication.
  325. """
  326. class PickleBlob(Blob):
  327. bin = Pickle()
  328. # Disable the cache, which holds strong references.
  329. self.get_cache(self.store).set_size(0)
  330. blob = self.store.get(Blob, 20)
  331. blob.bin = "\x80\x02}q\x01U\x01aK\x01s."
  332. self.store.flush()
  333. del blob
  334. gc.collect()
  335. pickle_blob = self.store.get(PickleBlob, 20)
  336. obj_info = get_obj_info(pickle_blob)
  337. del pickle_blob
  338. gc.collect()
  339. self.assertEquals(obj_info.get_obj(), None)
  340. pickle_blob = self.store.get(PickleBlob, 20)
  341. pickle_blob.bin = "foobin"
  342. events = []
  343. obj_info.event.hook("changed", lambda *args: events.append(args))
  344. self.store.flush()
  345. self.assertEquals(len(events), 1)
  346. def test_wb_flush_event_with_deleted_object_before_flush(self):
  347. """
  348. When an object is deleted before flush and it contains mutable
  349. variables, those variables unhook from the global event system to
  350. prevent a leak.
  351. """
  352. class PickleBlob(Blob):
  353. bin = Pickle()
  354. # Disable the cache, which holds strong references.
  355. self.get_cache(self.store).set_size(0)
  356. blob = self.store.get(Blob, 20)
  357. blob.bin = "\x80\x02}q\x01U\x01aK\x01s."
  358. self.store.flush()
  359. del blob
  360. gc.collect()
  361. pickle_blob = self.store.get(PickleBlob, 20)
  362. pickle_blob.bin = "foobin"
  363. del pickle_blob
  364. self.store.flush()
  365. self.assertEquals(self.store._event._hooks["flush"], set())
  366. def test_mutable_variable_detect_change_from_alive(self):
  367. """
  368. Changes in a mutable variable like a L{PickleVariable} are correctly
  369. detected, even if the object comes from the alive cache.
  370. """
  371. class PickleBlob(Blob):
  372. bin = Pickle()
  373. blob = PickleBlob()
  374. blob.bin = {"k": "v"}
  375. blob.id = 4000
  376. self.store.add(blob)
  377. self.store.commit()
  378. blob = self.store.find(PickleBlob, PickleBlob.id == 4000).one()
  379. blob.bin["k1"] = "v1"
  380. self.store.commit()
  381. blob = self.store.find(PickleBlob, PickleBlob.id == 4000).one()
  382. self.assertEquals(blob.bin, {"k1": "v1", "k": "v"})
  383. def test_wb_checkpoint_doesnt_override_changed(self):
  384. """
  385. This test ensures that we don't uselessly checkpoint when getting back
  386. objects from the alive cache, which would hide changed values from the
  387. store.
  388. """
  389. foo = self.store.get(Foo, 20)
  390. foo.title = u"changed"
  391. self.store.block_implicit_flushes()
  392. foo2 = self.store.find(Foo, Foo.id == 20).one()
  393. self.store.unblock_implicit_flushes()
  394. self.store.commit()
  395. foo3 = self.store.find(Foo, Foo.id == 20).one()
  396. self.assertEquals(foo3.title, u"changed")
  397. def test_obj_info_with_deleted_object_with_get(self):
  398. # Same thing, but using get rather than find.
  399. # Disable the cache, which holds strong references.
  400. self.get_cache(self.store).set_size(0)
  401. foo = self.store.get(Foo, 20)
  402. foo.tainted = True
  403. obj_info = get_obj_info(foo)
  404. del foo
  405. gc.collect()
  406. self.assertEquals(obj_info.get_obj(), None)
  407. foo = self.store.get(Foo, 20)
  408. self.assertTrue(foo)
  409. self.assertFalse(getattr(foo, "tainted", False))
  410. def test_delete_object_when_obj_info_is_dirty(self):
  411. """Object should stay in memory if dirty."""
  412. # Disable the cache, which holds strong references.
  413. self.get_cache(self.store).set_size(0)
  414. foo = self.store.get(Foo, 20)
  415. foo.title = u"Changed"
  416. foo.tainted = True
  417. obj_info = get_obj_info(foo)
  418. del foo
  419. gc.collect()
  420. self.assertTrue(obj_info.get_obj())
  421. def test_get_tuple(self):
  422. class MyFoo(Foo):
  423. __storm_primary__ = "title", "id"
  424. foo = self.store.get(MyFoo, (u"Title 30", 10))
  425. self.assertEquals(foo.id, 10)
  426. self.assertEquals(foo.title, "Title 30")
  427. foo = self.store.get(MyFoo, (u"Title 20", 10))
  428. self.assertEquals(foo, None)
  429. def test_of(self):
  430. foo = self.store.get(Foo, 10)
  431. self.assertEquals(Store.of(foo), self.store)
  432. self.assertEquals(Store.of(Foo()), None)
  433. self.assertEquals(Store.of(object()), None)
  434. def test_is_empty(self):
  435. result = self.store.find(Foo, id=300)
  436. self.assertEquals(result.is_empty(), True)
  437. result = self.store.find(Foo, id=30)
  438. self.assertEquals(result.is_empty(), False)
  439. def test_is_empty_strips_order_by(self):
  440. """
  441. L{ResultSet.is_empty} strips the C{ORDER BY} clause, if one is
  442. present, since it isn't required to actually determine if a result set
  443. has any matching rows. This should provide a performance improvement
  444. when the ordered result set would be large.
  445. """
  446. stream = StringIO()
  447. self.addCleanup(debug, False)
  448. debug(True, stream)
  449. result = self.store.find(Foo, Foo.id == 300)
  450. result.order_by(Foo.id)
  451. self.assertEqual(True, result.is_empty())
  452. self.assertNotIn("ORDER BY", stream.getvalue())
  453. def test_is_empty_with_composed_key(self):
  454. result = self.store.find(Link, foo_id=300, bar_id=3000)
  455. self.assertEquals(result.is_empty(), True)
  456. result = self.store.find(Link, foo_id=30, bar_id=300)
  457. self.assertEquals(result.is_empty(), False)
  458. def test_is_empty_with_expression_find(self):
  459. result = self.store.find(Foo.title, Foo.id == 300)
  460. self.assertEquals(result.is_empty(), True)
  461. result = self.store.find(Foo.title, Foo.id == 30)
  462. self.assertEquals(result.is_empty(), False)
  463. def test_find_iter(self):
  464. result = self.store.find(Foo)
  465. lst = [(foo.id, foo.title) for foo in result]
  466. lst.sort()
  467. self.assertEquals(lst, [
  468. (10, "Title 30"),
  469. (20, "Title 20"),
  470. (30, "Title 10"),
  471. ])
  472. def test_find_from_cache(self):
  473. foo = self.store.get(Foo, 10)
  474. self.assertTrue(self.store.find(Foo, id=10).one() is foo)
  475. def test_find_expr(self):
  476. result = self.store.find(Foo, Foo.id == 20,
  477. Foo.title == u"Title 20")
  478. self.assertEquals([(foo.id, foo.title) for foo in result], [
  479. (20, "Title 20"),
  480. ])
  481. result = self.store.find(Foo, Foo.id == 10,
  482. Foo.title == u"Title 20")
  483. self.assertEquals([(foo.id, foo.title) for foo in result], [
  484. ])
  485. def test_find_sql(self):
  486. foo = self.store.find(Foo, SQL("foo.id = 20")).one()
  487. self.assertEquals(foo.title, "Title 20")
  488. def test_find_str(self):
  489. foo = self.store.find(Foo, "foo.id = 20").one()
  490. self.assertEquals(foo.title, "Title 20")
  491. def test_find_keywords(self):
  492. result = self.store.find(Foo, id=20, title=u"Title 20")
  493. self.assertEquals([(foo.id, foo.title) for foo in result], [
  494. (20, u"Title 20")
  495. ])
  496. result = self.store.find(Foo, id=10, title=u"Title 20")
  497. self.assertEquals([(foo.id, foo.title) for foo in result], [
  498. ])
  499. def test_find_order_by(self, *args):
  500. result = self.store.find(Foo).order_by(Foo.title)
  501. lst = [(foo.id, foo.title) for foo in result]
  502. self.assertEquals(lst, [
  503. (30, "Title 10"),
  504. (20, "Title 20"),
  505. (10, "Title 30"),
  506. ])
  507. def test_find_order_asc(self, *args):
  508. result = self.store.find(Foo).order_by(Asc(Foo.title))
  509. lst = [(foo.id, foo.title) for foo in result]
  510. self.assertEquals(lst, [
  511. (30, "Title 10"),
  512. (20, "Title 20"),
  513. (10, "Title 30"),
  514. ])
  515. def test_find_order_desc(self, *args):
  516. result = self.store.find(Foo).order_by(Desc(Foo.title))
  517. lst = [(foo.id, foo.title) for foo in result]
  518. self.assertEquals(lst, [
  519. (10, "Title 30"),
  520. (20, "Title 20"),
  521. (30, "Title 10"),
  522. ])
  523. def test_find_default_order_asc(self):
  524. class MyFoo(Foo):
  525. __storm_order__ = "title"
  526. result = self.store.find(MyFoo)
  527. lst = [(foo.id, foo.title) for foo in result]
  528. self.assertEquals(lst, [
  529. (30, "Title 10"),
  530. (20, "Title 20"),
  531. (10, "Title 30"),
  532. ])
  533. def test_find_default_order_desc(self):
  534. class MyFoo(Foo):
  535. __storm_order__ = "-title"
  536. result = self.store.find(MyFoo)
  537. lst = [(foo.id, foo.title) for foo in result]
  538. self.assertEquals(lst, [
  539. (10, "Title 30"),
  540. (20, "Title 20"),
  541. (30, "Title 10"),
  542. ])
  543. def test_find_default_order_with_tuple(self):
  544. class MyLink(Link):
  545. __storm_order__ = ("foo_id", "-bar_id")
  546. result = self.store.find(MyLink)
  547. lst = [(link.foo_id, link.bar_id) for link in result]
  548. self.assertEquals(lst, [
  549. (10, 300),
  550. (10, 200),
  551. (10, 100),
  552. (20, 200),
  553. (20, 100),
  554. (30, 300),
  555. ])
  556. def test_find_default_order_with_tuple_and_expr(self):
  557. class MyLink(Link):
  558. __storm_order__ = ("foo_id", Desc(Link.bar_id))
  559. result = self.store.find(MyLink)
  560. lst = [(link.foo_id, link.bar_id) for link in result]
  561. self.assertEquals(lst, [
  562. (10, 300),
  563. (10, 200),
  564. (10, 100),
  565. (20, 200),
  566. (20, 100),
  567. (30, 300),
  568. ])
  569. def test_find_index(self):
  570. """
  571. L{ResultSet.__getitem__} returns the object at the specified index.
  572. if a slice is used, a new L{ResultSet} is returned configured with the
  573. appropriate offset and limit.
  574. """
  575. foo = self.store.find(Foo).order_by(Foo.title)[0]
  576. self.assertEquals(foo.id, 30)
  577. self.assertEquals(foo.title, "Title 10")
  578. foo = self.store.find(Foo).order_by(Foo.title)[1]
  579. self.assertEquals(foo.id, 20)
  580. self.assertEquals(foo.title, "Title 20")
  581. foo = self.store.find(Foo).order_by(Foo.title)[2]
  582. self.assertEquals(foo.id, 10)
  583. self.assertEquals(foo.title, "Title 30")
  584. foo = self.store.find(Foo).order_by(Foo.title)[1:][1]
  585. self.assertEquals(foo.id, 10)
  586. self.assertEquals(foo.title, "Title 30")
  587. result = self.store.find(Foo).order_by(Foo.title)
  588. self.assertRaises(IndexError, result.__getitem__, 3)
  589. def test_find_slice(self):
  590. result = self.store.find(Foo).order_by(Foo.title)[1:2]
  591. lst = [(foo.id, foo.title) for foo in result]
  592. self.assertEquals(lst,
  593. [(20, "Title 20")])
  594. def test_find_slice_offset(self):
  595. result = self.store.find(Foo).order_by(Foo.title)[1:]
  596. lst = [(foo.id, foo.title) for foo in result]
  597. self.assertEquals(lst,
  598. [(20, "Title 20"),
  599. (10, "Title 30")])
  600. def test_find_slice_offset_any(self):
  601. foo = self.store.find(Foo).order_by(Foo.title)[1:].any()
  602. self.assertEquals(foo.id, 20)
  603. self.assertEquals(foo.title, "Title 20")
  604. def test_find_slice_offset_one(self):
  605. foo = self.store.find(Foo).order_by(Foo.title)[1:2].one()
  606. self.assertEquals(foo.id, 20)
  607. self.assertEquals(foo.title, "Title 20")
  608. def test_find_slice_offset_first(self):
  609. foo = self.store.find(Foo).order_by(Foo.title)[1:].first()
  610. self.assertEquals(foo.id, 20)
  611. self.assertEquals(foo.title, "Title 20")
  612. def test_find_slice_offset_last(self):
  613. foo = self.store.find(Foo).order_by(Foo.title)[1:].last()
  614. self.assertEquals(foo.id, 10)
  615. self.assertEquals(foo.title, "Title 30")
  616. def test_find_slice_limit(self):
  617. result = self.store.find(Foo).order_by(Foo.title)[:2]
  618. lst = [(foo.id, foo.title) for foo in result]
  619. self.assertEquals(lst,
  620. [(30, "Title 10"),
  621. (20, "Title 20")])
  622. def test_find_slice_limit_last(self):
  623. result = self.store.find(Foo).order_by(Foo.title)[:2]
  624. self.assertRaises(FeatureError, result.last)
  625. def test_find_slice_slice(self):
  626. result = self.store.find(Foo).order_by(Foo.title)[0:2][1:3]
  627. lst = [(foo.id, foo.title) for foo in result]
  628. self.assertEquals(lst,
  629. [(20, "Title 20")])
  630. result = self.store.find(Foo).order_by(Foo.title)[:2][1:3]
  631. lst = [(foo.id, foo.title) for foo in result]
  632. self.assertEquals(lst,
  633. [(20, "Title 20")])
  634. result = self.store.find(Foo).order_by(Foo.title)[1:3][0:1]
  635. lst = [(foo.id, foo.title) for foo in result]
  636. self.assertEquals(lst,
  637. [(20, "Title 20")])
  638. result = self.store.find(Foo).order_by(Foo.title)[1:3][:1]
  639. lst = [(foo.id, foo.title) for foo in result]
  640. self.assertEquals(lst,
  641. [(20, "Title 20")])
  642. result = self.store.find(Foo).order_by(Foo.title)[5:5][1:1]
  643. lst = [(foo.id, foo.title) for foo in result]
  644. self.assertEquals(lst, [])
  645. def test_find_slice_order_by(self):
  646. result = self.store.find(Foo)[2:]
  647. self.assertRaises(FeatureError, result.order_by, None)
  648. result = self.store.find(Foo)[:2]
  649. self.assertRaises(FeatureError, result.order_by, None)
  650. def test_find_slice_remove(self):
  651. result = self.store.find(Foo)[2:]
  652. self.assertRaises(FeatureError, result.remove)
  653. result = self.store.find(Foo)[:2]
  654. self.assertRaises(FeatureError, result.remove)
  655. def test_find_contains(self):
  656. foo = self.store.get(Foo, 10)
  657. result = self.store.find(Foo)
  658. self.assertEquals(foo in result, True)
  659. result = self.store.find(Foo, Foo.id == 20)
  660. self.assertEquals(foo in result, False)
  661. result = self.store.find(Foo, "foo.id = 20")
  662. self.assertEquals(foo in result, False)
  663. def test_find_contains_wrong_type(self):
  664. foo = self.store.get(Foo, 10)
  665. bar = self.store.get(Bar, 200)
  666. self.assertRaises(TypeError, operator.contains,
  667. self.store.find(Foo), bar)
  668. self.assertRaises(TypeError, operator.contains,
  669. self.store.find((Foo,)), foo)
  670. self.assertRaises(TypeError, operator.contains,
  671. self.store.find(Foo), (foo,))
  672. self.assertRaises(TypeError, operator.contains,
  673. self.store.find((Foo, Bar)), (bar, foo))
  674. def test_find_contains_does_not_use_iter(self):
  675. def no_iter(self):
  676. raise RuntimeError()
  677. orig_iter = ResultSet.__iter__
  678. ResultSet.__iter__ = no_iter
  679. try:
  680. foo = self.store.get(Foo, 10)
  681. result = self.store.find(Foo)
  682. self.assertEquals(foo in result, True)
  683. finally:
  684. ResultSet.__iter__ = orig_iter
  685. def test_find_contains_with_composed_key(self):
  686. link = self.store.get(Link, (10, 100))
  687. result = self.store.find(Link, Link.foo_id == 10)
  688. self.assertEquals(link in result, True)
  689. result = self.store.find(Link, Link.bar_id == 200)
  690. self.assertEquals(link in result, False)
  691. def test_find_contains_with_set_expression(self):
  692. foo = self.store.get(Foo, 10)
  693. result1 = self.store.find(Foo, Foo.id == 10)
  694. result2 = self.store.find(Foo, Foo.id != 10)
  695. self.assertEquals(foo in result1.union(result2), True)
  696. if self.__class__.__name__.startswith("MySQL"):
  697. return
  698. self.assertEquals(foo in result1.intersection(result2), False)
  699. self.assertEquals(foo in result1.intersection(result1), True)
  700. self.assertEquals(foo in result1.difference(result2), True)
  701. self.assertEquals(foo in result1.difference(result1), False)
  702. def test_find_any(self, *args):
  703. """
  704. L{ResultSet.any} returns an arbitrary objects from the result set.
  705. """
  706. self.assertNotEqual(None, self.store.find(Foo).any())
  707. self.assertEqual(None, self.store.find(Foo, id=40).any())
  708. def test_find_any_strips_order_by(self):
  709. """
  710. L{ResultSet.any} strips the C{ORDER BY} clause, if one is present,
  711. since it isn't required. This should provide a performance
  712. improvement when the ordered result set would be large.
  713. """
  714. stream = StringIO()
  715. self.addCleanup(debug, False)
  716. debug(True, stream)
  717. result = self.store.find(Foo, Foo.id == 300)
  718. result.order_by(Foo.id)
  719. result.any()
  720. self.assertNotIn("ORDER BY", stream.getvalue())
  721. def test_find_first(self, *args):
  722. self.assertRaises(UnorderedError, self.store.find(Foo).first)
  723. foo = self.store.find(Foo).order_by(Foo.title).first()
  724. self.assertEquals(foo.id, 30)
  725. self.assertEquals(foo.title, "Title 10")
  726. foo = self.store.find(Foo).order_by(Foo.id).first()
  727. self.assertEquals(foo.id, 10)
  728. self.assertEquals(foo.title, "Title 30")
  729. foo = self.store.find(Foo, id=40).order_by(Foo.id).first()
  730. self.assertEquals(foo, None)
  731. def test_find_last(self, *args):
  732. self.assertRaises(UnorderedError, self.store.find(Foo).last)
  733. foo = self.store.find(Foo).order_by(Foo.title).last()
  734. self.assertEquals(foo.id, 10)
  735. self.assertEquals(foo.title, "Title 30")
  736. foo = self.store.find(Foo).order_by(Foo.id).last()
  737. self.assertEquals(foo.id, 30)
  738. self.assertEquals(foo.title, "Title 10")
  739. foo = self.store.find(Foo, id=40).order_by(Foo.id).last()
  740. self.assertEquals(foo, None)
  741. def test_find_last_desc(self, *args):
  742. foo = self.store.find(Foo).order_by(Desc(Foo.title)).last()
  743. self.assertEquals(foo.id, 30)
  744. self.assertEquals(foo.title, "Title 10")
  745. foo = self.store.find(Foo).order_by(Asc(Foo.id)).last()
  746. self.assertEquals(foo.id, 30)
  747. self.assertEquals(foo.title, "Title 10")
  748. def test_find_one(self, *args):
  749. self.assertRaises(NotOneError, self.store.find(Foo).one)
  750. foo = self.store.find(Foo, id=10).one()
  751. self.assertEquals(foo.id, 10)
  752. self.assertEquals(foo.title, "Title 30")
  753. foo = self.store.find(Foo, id=40).one()
  754. self.assertEquals(foo, None)
  755. def test_find_count(self):
  756. self.assertEquals(self.store.find(Foo).count(), 3)
  757. def test_find_count_after_slice(self):
  758. """
  759. When we slice a ResultSet obtained after a set operation (like union),
  760. we get a fresh select that doesn't modify the limit and offset
  761. attribute of the original ResultSet.
  762. """
  763. result1 = self.store.find(Foo, Foo.id == 10)
  764. result2 = self.store.find(Foo, Foo.id == 20)
  765. result3 = result1.union(result2)
  766. result3.order_by(Foo.id)
  767. self.assertEquals(result3.count(), 2)
  768. result_slice = list(result3[:2])
  769. self.assertEquals(result3.count(), 2)
  770. def test_find_count_column(self):
  771. self.assertEquals(self.store.find(Link).count(Link.foo_id), 6)
  772. def test_find_count_column_distinct(self):
  773. count = self.store.find(Link).count(Link.foo_id, distinct=True)
  774. self.assertEquals(count, 3)
  775. def test_find_limit_count(self):
  776. result = self.store.find(Link.foo_id)
  777. result.config(limit=2)
  778. count = result.count()
  779. self.assertEquals(count, 2)
  780. def test_find_offset_count(self):
  781. result = self.store.find(Link.foo_id)
  782. result.config(offset=3)
  783. count = result.count()
  784. self.assertEquals(count, 3)
  785. def test_find_sliced_count(self):
  786. result = self.store.find(Link.foo_id)
  787. count = result[2:4].count()
  788. self.assertEquals(count, 2)
  789. def test_find_distinct_count(self):
  790. result = self.store.find(Link.foo_id)
  791. result.config(distinct=True)
  792. count = result.count()
  793. self.assertEquals(count, 3)
  794. def test_find_distinct_order_by_limit_count(self):
  795. result = self.store.find(Foo)
  796. result.order_by(Foo.title)
  797. result.config(distinct=True, limit=3)
  798. count = result.count()
  799. self.assertEquals(count, 3)
  800. def test_find_distinct_count_multiple_columns(self):
  801. result = self.store.find((Link.foo_id, Link.bar_id))
  802. result.config(distinct=True)
  803. count = result.count()
  804. self.assertEquals(count, 6)
  805. def test_find_count_column_with_implicit_distinct(self):
  806. result = self.store.find(Link)
  807. result.config(distinct=True)
  808. count = result.count(Link.foo_id)
  809. self.assertEquals(count, 6)
  810. def test_find_max(self):
  811. self.assertEquals(self.store.find(Foo).max(Foo.id), 30)
  812. def test_find_max_expr(self):
  813. self.assertEquals(self.store.find(Foo).max(Foo.id + 1), 31)
  814. def test_find_max_unicode(self):
  815. title = self.store.find(Foo).max(Foo.title)
  816. self.assertEquals(title, "Title 30")
  817. self.assertTrue(isinstance(title, unicode))
  818. def test_find_max_with_empty_result_and_disallow_none(self):
  819. class Bar(object):
  820. __storm_table__ = "bar"
  821. id = Int(primary=True)
  822. foo_id = Int(allow_none=False)
  823. result = self.store.find(Bar, Bar.id > 1000)
  824. self.assertTrue(result.is_empty())
  825. self.assertEquals(result.max(Bar.foo_id), None)
  826. def test_find_min(self):
  827. self.assertEquals(self.store.find(Foo).min(Foo.id), 10)
  828. def test_find_min_expr(self):
  829. self.assertEquals(self.store.find(Foo).min(Foo.id - 1), 9)
  830. def test_find_min_unicode(self):
  831. title = self.store.find(Foo).min(Foo.title)
  832. self.assertEquals(title, "Title 10")
  833. self.assertTrue(isinstance(title, unicode))
  834. def test_find_min_with_empty_result_and_disallow_none(self):
  835. class Bar(object):
  836. __storm_table__ = "bar"
  837. id = Int(primary=True)
  838. foo_id = Int(allow_none=False)
  839. result = self.store.find(Bar, Bar.id > 1000)
  840. self.assertTrue(result.is_empty())
  841. self.assertEquals(result.min(Bar.foo_id), None)
  842. def test_find_avg(self):
  843. self.assertEquals(self.store.find(Foo).avg(Foo.id), 20)
  844. def test_find_avg_expr(self):
  845. self.assertEquals(self.store.find(Foo).avg(Foo.id + 10), 30)
  846. def test_find_avg_float(self):
  847. foo = Foo()
  848. foo.id = 15
  849. foo.title = u"Title 15"
  850. self.store.add(foo)
  851. self.assertEquals(self.store.find(Foo).avg(Foo.id), 18.75)
  852. def test_find_sum(self):
  853. self.assertEquals(self.store.find(Foo).sum(Foo.id), 60)
  854. def test_find_sum_expr(self):
  855. self.assertEquals(self.store.find(Foo).sum(Foo.id * 2), 120)
  856. def test_find_sum_with_empty_result_and_disallow_none(self):
  857. class Bar(object):
  858. __storm_table__ = "bar"
  859. id = Int(primary=True)
  860. foo_id = Int(allow_none=False)
  861. result = self.store.find(Bar, Bar.id > 1000)
  862. self.assertTrue(result.is_empty())
  863. self.assertEquals(result.sum(Bar.foo_id), None)
  864. def test_find_max_order_by(self):
  865. """Interaction between order by and aggregation shouldn't break."""
  866. result = self.store.find(Foo)
  867. self.assertEquals(result.order_by(Foo.id).max(Foo.id), 30)
  868. def test_find_get_select_expr_without_columns(self):
  869. """
  870. A L{FeatureError} is raised if L{ResultSet.get_select_expr} is called
  871. without a list of L{Column}s.
  872. """
  873. result = self.store.find(Foo)
  874. self.assertRaises(FeatureError, result.get_select_expr)
  875. def test_find_get_select_expr(self):
  876. """
  877. Only the specified L{Column}s are included in the L{Select} expression
  878. provided by L{ResultSet.get_select_expr}.
  879. """
  880. foo = self.store.get(Foo, 10)
  881. result1 = self.store.find(Foo, Foo.id <= 10)
  882. subselect = result1.get_select_expr(Foo.id)
  883. self.assertEqual((Foo.id,), subselect.columns)
  884. result2 = self.store.find(Foo, Foo.id.is_in(subselect))
  885. self.assertEqual([foo], list(result2))
  886. def test_find_get_select_expr_with_set_expression(self):
  887. """
  888. A L{FeatureError} is raised if L{ResultSet.get_select_expr} is used
  889. with a L{ResultSet} that represents a set expression, such as a union.
  890. """
  891. result1 = self.store.find(Foo, Foo.id == 10)
  892. result2 = self.store.find(Foo, Foo.id == 20)
  893. result3 = result1.union(result2)
  894. self.assertRaises(FeatureError, result3.get_select_expr, Foo.id)
  895. def test_find_values(self):
  896. values = self.store.find(Foo).order_by(Foo.id).values(Foo.id)
  897. self.assertEquals(list(values), [10, 20, 30])
  898. values = self.store.find(Foo).order_by(Foo.id).values(Foo.title)
  899. values = list(values)
  900. self.assertEquals(values, ["Title 30", "Title 20", "Title 10"])
  901. self.assertEquals([type(value) for value in values],
  902. [unicode, unicode, unicode])
  903. def test_find_multiple_values(self):
  904. result = self.store.find(Foo).order_by(Foo.id)
  905. values = result.values(Foo.id, Foo.title)
  906. self.assertEquals(list(values),
  907. [(10, "Title 30"),
  908. (20, "Title 20"),
  909. (30, "Title 10")])
  910. def test_find_values_with_no_arguments(self):
  911. result = self.store.find(Foo).order_by(Foo.id)
  912. self.assertRaises(FeatureError, result.values().next)
  913. def test_find_slice_values(self):
  914. values = self.store.find(Foo).order_by(Foo.id)[1:2].values(Foo.id)
  915. self.assertEquals(list(values), [20])
  916. def test_find_values_with_set_expression(self):
  917. """
  918. A L{FeatureError} is raised if L{ResultSet.values} is used with a
  919. L{ResultSet} that represents a set expression, such as a union.
  920. """
  921. result1 = self.store.find(Foo, Foo.id == 10)
  922. result2 = self.store.find(Foo, Foo.id == 20)
  923. result3 = result1.union(result2)
  924. self.assertRaises(FeatureError, list, result3.values(Foo.id))
  925. def test_find_remove(self):
  926. self.store.find(Foo, Foo.id == 20).remove()
  927. self.assertEquals(self.get_items(), [
  928. (10, "Title 30"),
  929. (30, "Title 10"),
  930. ])
  931. def test_find_cached(self):
  932. foo = self.store.get(Foo, 20)
  933. bar = self.store.get(Bar, 200)
  934. self.assertTrue(foo)
  935. self.assertTrue(bar)
  936. self.assertEquals(self.store.find(Foo).cached(), [foo])
  937. def test_find_cached_where(self):
  938. foo1 = self.store.get(Foo, 10)
  939. foo2 = self.store.get(Foo, 20)
  940. bar = self.store.get(Bar, 200)
  941. self.assertTrue(foo1)
  942. self.assertTrue(foo2)
  943. self.assertTrue(bar)
  944. self.assertEquals(self.store.find(Foo, title=u"Title 20").cached(),
  945. [foo2])
  946. def test_find_cached_invalidated(self):
  947. foo = self.store.get(Foo, 20)
  948. self.store.invalidate(foo)
  949. self.assertEquals(self.store.find(Foo).cached(), [foo])
  950. def test_find_cached_invalidated_and_deleted(self):
  951. foo = self.store.get(Foo, 20)
  952. self.store.execute("DELETE FROM foo WHERE id=20")
  953. self.store.invalidate(foo)
  954. # Do not look for the primary key (id), since it's able to get
  955. # it without touching the database. Use the title instead.
  956. self.assertEquals(self.store.find(Foo, title=u"Title 20").cached(), [])
  957. def test_find_cached_with_info_alive_and_object_dead(self):
  958. # Disable the cache, which holds strong references.
  959. self.get_cache(self.store).set_size(0)
  960. foo = self.store.get(Foo, 20)
  961. foo.tainted = True
  962. obj_info = get_obj_info(foo)
  963. del foo
  964. gc.collect()
  965. cached = self.store.find(Foo).cached()
  966. self.assertEquals(len(cached), 1)
  967. foo = self.store.get(Foo, 20)
  968. self.assertFalse(hasattr(foo, "tainted"))
  969. def test_using_find_join(self):
  970. bar = self.store.get(Bar, 100)
  971. bar.foo_id = None
  972. tables = self.store.using(Foo, LeftJoin(Bar, Bar.foo_id == Foo.id))
  973. result = tables.find(Bar).order_by(Foo.id, Bar.id)
  974. lst = [bar and (bar.id, bar.title) for bar in result]
  975. self.assertEquals(lst, [
  976. None,
  977. (200, u"Title 200"),
  978. (300, u"Title 100"),
  979. ])
  980. def test_using_find_with_strings(self):
  981. foo = self.store.using("foo").find(Foo, id=10).one()
  982. self.assertEquals(foo.title, "Title 30")
  983. foo = self.store.using("foo", "bar").find(Foo, id=10).any()
  984. self.assertEquals(foo.title, "Title 30")
  985. def test_using_find_join_with_strings(self):
  986. bar = self.store.get(Bar, 100)
  987. bar.foo_id = None
  988. tables = self.store.using(LeftJoin("foo", "bar",
  989. "bar.foo_id = foo.id"))
  990. result = tables.find(Bar).order_by(Foo.id, Bar.id)
  991. lst = [bar and (bar.id, bar.title) for bar in result]
  992. self.assertEquals(lst, [
  993. None,
  994. (200, u"Title 200"),
  995. (300, u"Title 100"),
  996. ])
  997. def test_find_tuple(self):
  998. bar = self.store.get(Bar, 200)
  999. bar.foo_id = None
  1000. result = self.store.find((Foo, Bar), Bar.foo_id == Foo.id)
  1001. result = result.order_by(Foo.id)
  1002. lst = [(foo and (foo.id, foo.title), bar and (bar.id, bar.title))
  1003. for (foo, bar) in result]
  1004. self.assertEquals(lst, [
  1005. ((10, u"Title 30"), (100, u"Title 300")),
  1006. ((30, u"Title 10"), (300, u"Title 100")),
  1007. ])
  1008. def test_find_tuple_using(self):
  1009. bar = self.store.get(Bar, 200)
  1010. bar.foo_id = None
  1011. tables = self.store.using(Foo, LeftJoin(Bar, Bar.foo_id == Foo.id))
  1012. result = tables.find((Foo, Bar)).order_by(Foo.id)
  1013. lst = [(foo and (foo.id, foo.title), bar and (bar.id, bar.title))
  1014. for (foo, bar) in result]
  1015. self.assertEquals(lst, [
  1016. ((10, u"Title 30"), (100, u"Title 300")),
  1017. ((20, u"Title 20"), None),
  1018. ((30, u"Title 10"), (300, u"Title 100")),
  1019. ])
  1020. def test_find_tuple_using_with_disallow_none(self):
  1021. class Bar(object):
  1022. __storm_table__ = "bar"
  1023. id = Int(primary=True, allow_none=False)
  1024. title = Unicode()
  1025. foo_id = Int()
  1026. foo = Reference(foo_id, Foo.id)
  1027. bar = self.store.get(Bar, 200)
  1028. self.store.remove(bar)
  1029. tables = self.store.using(Foo, LeftJoin(Bar, Bar.foo_id == Foo.id))
  1030. result = tables.find((Foo, Bar)).order_by(Foo.id)
  1031. lst = [(foo and (foo.id, foo.title), bar and (bar.id, bar.title))
  1032. for (foo, bar) in result]
  1033. self.assertEquals(lst, [
  1034. ((10, u"Title 30"), (100, u"Title 300")),
  1035. ((20, u"Title 20"), None),
  1036. ((30, u"Title 10"), (300, u"Title 100")),
  1037. ])
  1038. def test_find_tuple_using_skip_when_none(self):
  1039. bar = self.store.get(Bar, 200)
  1040. bar.foo_id = None
  1041. tables = self.store.using(Foo,
  1042. LeftJoin(Bar, Bar.foo_id == Foo.id),
  1043. LeftJoin(Link, Link.bar_id == Bar.id))
  1044. result = tables.find((Bar, Link)).order_by(Foo.id, Bar.id, Link.foo_id)
  1045. lst = [(bar and (bar.id, bar.title),
  1046. link and (link.bar_id, link.foo_id))
  1047. for (bar, link) in result]
  1048. self.assertEquals(lst, [
  1049. ((100, u"Title 300"), (100, 10)),
  1050. ((100, u"Title 300"), (100, 20)),
  1051. (None, None),
  1052. ((300, u"Title 100"), (300, 10)),
  1053. ((300, u"Title 100"), (300, 30)),
  1054. ])
  1055. def test_find_tuple_contains(self):
  1056. foo = self.store.get(Foo, 10)
  1057. bar = self.store.get(Bar, 100)
  1058. bar200 = self.store.get(Bar, 200)
  1059. result = self.store.find((Foo, Bar), Bar.foo_id == Foo.id)
  1060. self.assertEquals((foo, bar) in result, True)
  1061. self.assertEquals((foo, bar200) in result, False)
  1062. def test_find_tuple_contains_with_set_expression(self):
  1063. foo = self.store.get(Foo, 10)
  1064. bar = self.store.get(Bar, 100)
  1065. bar200 = self.store.get(Bar, 200)
  1066. result1 = self.store.find((Foo, Bar), Bar.foo_id == Foo.id)
  1067. result2 = self.store.find((Foo, Bar), Bar.foo_id == Foo.id)
  1068. self.assertEquals((foo, bar) in result1.union(result2), True)
  1069. if self.__class__.__name__.startswith("MySQL"):
  1070. return
  1071. self.assertEquals((foo, bar) in result1.intersection(result2), True)
  1072. self.assertEquals((foo, bar) in result1.difference(result2), False)
  1073. def test_find_tuple_any(self):
  1074. bar = self.store.get(Bar, 200)
  1075. bar.foo_id = None
  1076. result = self.store.find((Foo, Bar), Bar.foo_id == Foo.id)
  1077. foo, bar = result.order_by(Foo.id).any()
  1078. self.assertEquals(foo.id, 10)
  1079. self.assertEquals(foo.title, u"Title 30")
  1080. self.assertEquals(bar.id, 100)
  1081. self.assertEquals(bar.title, u"Title 300")
  1082. def test_find_tuple_first(self):
  1083. bar = self.store.get(Bar, 200)
  1084. bar.foo_id = None
  1085. result = self.store.find((Foo, Bar), Bar.foo_id == Foo.id)
  1086. foo, bar = result.order_by(Foo.id).first()
  1087. self.assertEquals(foo.id, 10)
  1088. self.assertEquals(foo.title, u"Title 30")
  1089. self.assertEquals(bar.id, 100)
  1090. self.assertEquals(bar.title, u"Title 300")
  1091. def test_find_tuple_last(self):
  1092. bar = self.store.get(Bar, 200)
  1093. bar.foo_id = None
  1094. result = self.store.find((Foo, Bar), Bar.foo_id == Foo.id)
  1095. foo, bar = result.order_by(Foo.id).last()
  1096. self.assertEquals(foo.id, 30)
  1097. self.assertEquals(foo.title, u"Title 10")
  1098. self.assertEquals(bar.id, 300)
  1099. self.assertEquals(bar.title, u"Title 100")
  1100. def test_find_tuple_one(self):
  1101. bar = self.store.get(Bar, 200)
  1102. bar.foo_id = None
  1103. result = self.store.find((Foo, Bar),
  1104. Bar.foo_id == Foo.id, Foo.id == 10)
  1105. foo, bar = result.order_by(Foo.id).one()
  1106. self.assertEquals(foo.id, 10)
  1107. self.assertEquals(foo.title, u"Title 30")
  1108. self.assertEquals(bar.id, 100)
  1109. self.assertEquals(bar.title, u"Title 300")
  1110. def test_find_tuple_count(self):
  1111. bar = self.store.get(Bar, 200)
  1112. bar.foo_id = None
  1113. result = self.store.find((Foo, Bar), Bar.foo_id == Foo.id)
  1114. self.assertEquals(result.count(), 2)
  1115. def test_find_tuple_remove(self):
  1116. result = self.store.find((Foo, Bar))
  1117. self.assertRaises(FeatureError, result.remove)
  1118. def test_find_tuple_set(self):
  1119. result = self.store.find((Foo, Bar))
  1120. self.assertRaises(FeatureError, result.set, title=u"Title 40")
  1121. def test_find_tuple_kwargs(self):
  1122. self.assertRaises(FeatureError,
  1123. self.store.find, (Foo, Bar), title=u"Title 10")
  1124. def test_find_tuple_cached(self):
  1125. result = self.store.find((Foo, Bar))
  1126. self.assertRaises(FeatureError, result.cached)
  1127. def test_find_using_cached(self):
  1128. result = self.store.using(Foo, Bar).find(Foo)
  1129. self.assertRaises(FeatureError, result.cached)
  1130. def test_find_with_expr(self):
  1131. result = self.store.find(Foo.title)
  1132. self.assertEquals(sorted(result),
  1133. [u"Title 10", u"Title 20", u"Title 30"])
  1134. def test_find_with_expr_uses_variable_set(self):
  1135. result = self.store.find(FooVariable.title,
  1136. FooVariable.id == 10)
  1137. self.assertEquals(list(result), [u"to_py(from_db(Title 30))"])
  1138. def test_find_tuple_with_expr(self):
  1139. result = self.store.find((Foo, Bar.id, Bar.title),
  1140. Bar.foo_id == Foo.id)
  1141. result.order_by(Foo.id)
  1142. self.assertEquals([(foo.id, foo.title, bar_id, bar_title)
  1143. for foo, bar_id, bar_title in result],
  1144. [(10, u"Title 30", 100, u"Title 300"),
  1145. (20, u"Title 20", 200, u"Title 200"),
  1146. (30, u"Title 10", 300, u"Title 100")])
  1147. def test_find_using_with_expr(self):
  1148. result = self.store.using(Foo).find(Foo.title)
  1149. self.assertEquals(sorted(result),
  1150. [u"Title 10", u"Title 20", u"Title 30"])
  1151. def test_find_with_expr_contains(self):
  1152. result = self.store.find(Foo.title)
  1153. self.assertEquals(u"Title 10" in result, True)
  1154. self.assertEquals(u"Title 42" in result, False)
  1155. def test_find_tuple_with_expr_contains(self):
  1156. foo = self.store.get(Foo, 10)
  1157. result = self.store.find((Foo, Bar.title),
  1158. Bar.foo_id == Foo.id)
  1159. self.assertEquals((foo, u"Title 300") in result, True)
  1160. self.assertEquals((foo, u"Title 100") in result, False)
  1161. def test_find_with_expr_contains_with_set_expression(self):
  1162. result1 = self.store.find(Foo.title)
  1163. result2 = self.store.find(Foo.title)
  1164. self.assertEquals(u"Title 10" in result1.union(result2), True)
  1165. if self.__class__.__name__.startswith("MySQL"):
  1166. return
  1167. self.assertEquals(u"Title 10" in result1.intersection(result2), True)
  1168. self.assertEquals(u"Title 10" in result1.difference(result2), False)
  1169. def test_find_with_expr_remove_unsupported(self):
  1170. result = self.store.find(Foo.title)
  1171. self.assertRaises(FeatureError, result.remove)
  1172. def test_find_tuple_with_expr_remove_unsupported(self):
  1173. result = self.store.find((Foo, Bar.title), Bar.foo_id == Foo.id)
  1174. self.assertRaises(FeatureError, result.remove)
  1175. def test_find_with_expr_count(self):
  1176. result = self.store.find(Foo.title)
  1177. self.assertEquals(result.count(), 3)
  1178. def test_find_tuple_with_expr_count(self):
  1179. result = self.store.find((Foo, Bar.title), Bar.foo_id == Foo.id)
  1180. self.assertEquals(result.count(), 3)
  1181. def test_find_with_expr_values(self):
  1182. result = self.store.find(Foo.title)
  1183. self.assertEquals(sorted(result.values(Foo.title)),
  1184. [u"Title 10", u"Title 20", u"Title 30"])
  1185. def test_find_tuple_with_expr_values(self):
  1186. result = self.store.find((Foo, Bar.title), Bar.foo_id == Foo.id)
  1187. self.assertEquals(sorted(result.values(Foo.title)),
  1188. [u"Title 10", u"Title 20", u"Title 30"])
  1189. def test_find_with_expr_set_unsupported(self):
  1190. result = self.store.find(Foo.title)
  1191. self.assertRaises(FeatureError, result.set)
  1192. def test_find_tuple_with_expr_set_unsupported(self):
  1193. result = self.store.find((Foo, Bar.title), Bar.foo_id == Foo.id)
  1194. self.assertRaises(FeatureError, result.set)
  1195. def test_find_with_expr_cached_unsupported(self):
  1196. result = self.store.find(Foo.title)
  1197. self.assertRaises(FeatureError, result.cached)
  1198. def test_find_tuple_with_expr_cached_unsupported(self):
  1199. result = self.store.find((Foo, Bar.title), Bar.foo_id == Foo.id)
  1200. self.assertRaises(FeatureError, result.cached)
  1201. def test_find_with_expr_union(self):
  1202. result1 = self.store.find(Foo.title, Foo.id == 10)
  1203. result2 = self.store.find(Foo.title, Foo.id != 10)
  1204. result = result1.union(result2)
  1205. self.assertEquals(sorted(result),
  1206. [u"Title 10", u"Title 20", u"Title 30",])
  1207. def test_find_alias_with_expr_union(self):
  1208. result1 = self.store.find(Alias(Foo.title, 'title'),
  1209. Foo.title == u"Title 30")
  1210. result2 = self.store.find(Alias(Bar.title, 'title'),
  1211. Bar.title == u"Title 100")
  1212. result = result1.union(result2)
  1213. self.assertEquals(sorted(result), [u'Title 100', u'Title 30'])
  1214. def test_find_tuple_with_expr_union(self):
  1215. result1 = self.store.find(
  1216. (Foo, Bar.title), Bar.foo_id == Foo.id, Bar.title == u"Title 100")
  1217. result2 = self.store.find(
  1218. (Foo, Bar.title), Bar.foo_id == Foo.id, Bar.title == u"Title 200")
  1219. result = result1.union(result2)
  1220. self.assertEquals(sorted((foo.id, title) for (foo, title) in result),
  1221. [(20, u"Title 200"), (30, u"Title 100")])
  1222. def test_get_does_not_validate(self):
  1223. def validator(object, attr, value):
  1224. self.fail("validator called with arguments (%r, %r, %r)" %
  1225. (object, attr, value))
  1226. class Foo(object):
  1227. __storm_table__ = "foo"
  1228. id = Int(primary=True)
  1229. title = Unicode(validator=validator)
  1230. foo = self.store.get(Foo, 10)
  1231. self.assertEqual(foo.title, "Title 30")
  1232. def test_get_does_not_validate_default_value(self):
  1233. def validator(object, attr, value):
  1234. self.fail("validator called with arguments (%r, %r, %r)" %
  1235. (object, attr, value))
  1236. class Foo(object):
  1237. __storm_table__ = "foo"
  1238. id = Int(primary=True)
  1239. title = Unicode(validator=validator, default=u"default value")
  1240. foo = self.store.get(Foo, 10)
  1241. self.assertEqual(foo.title, "Title 30")
  1242. def test_find_does_not_validate(self):
  1243. def validator(object, attr, value):
  1244. self.fail("validator called with arguments (%r, %r, %r)" %
  1245. (object, attr, value))
  1246. class Foo(object):
  1247. __storm_table__ = "foo"
  1248. id = Int(primary=True)
  1249. title = Unicode(validator=validator)
  1250. foo = self.store.find(Foo, Foo.id == 10).one()
  1251. self.assertEqual(foo.title, "Title 30")
  1252. def test_find_group_by(self):
  1253. result = self.store.find((Count(FooValue.id), Sum(FooValue.value1)))
  1254. result.group_by(FooValue.value2)
  1255. result.order_by(Count(FooValue.id), Sum(FooValue.value1))
  1256. result = list(result)
  1257. self.assertEquals(result, [(2L, 2L), (2L, 2L), (2L, 3L), (3L, 6L)])
  1258. def test_find_group_by_table(self):
  1259. result = self.store.find(
  1260. (Sum(FooValue.value2), Foo), Foo.id == FooValue.foo_id)
  1261. result.group_by(Foo)
  1262. foo1 = self.store.get(Foo, 10)
  1263. foo2 = self.store.get(Foo, 20)
  1264. self.assertEquals(list(result), [(5, foo1), (16, foo2)])
  1265. def test_find_group_by_table_contains(self):
  1266. result = self.store.find(
  1267. (Sum(FooValue.value2), Foo), Foo.id == FooValue.foo_id)
  1268. result.group_by(Foo)
  1269. foo1 = self.store.get(Foo, 10)
  1270. self.assertEquals((5, foo1) in result, True)
  1271. def test_find_group_by_multiple_tables(self):
  1272. result = self.store.find(
  1273. Sum(FooValue.value2), Foo.id == FooValue.foo_id)
  1274. result.group_by(Foo.id)
  1275. result.order_by(Sum(FooValue.value2))
  1276. result = list(result)
  1277. self.assertEquals(result, [5, 16])
  1278. result = self.store.find(
  1279. (Sum(FooValue.value2), Foo), Foo.id == FooValue.foo_id)
  1280. result.group_by(Foo)
  1281. result.order_by(Sum(FooValue.value2))
  1282. result = list(result)
  1283. foo1 = self.store.get(Foo, 10)
  1284. foo2 = self.store.get(Foo, 20)
  1285. self.assertEquals(result, [(5, foo1), (16, foo2)])
  1286. result = self.store.find(
  1287. (Foo.id, Sum(FooValue.value2), Avg(FooValue.value1)),
  1288. Foo.id == FooValue.foo_id)
  1289. result.group_by(Foo.id)
  1290. result.order_by(Foo.id)
  1291. result = list(result)
  1292. self.assertEquals(result, [(10, 5, 2),
  1293. (20, 16, 1)])
  1294. def test_find_group_by_having(self):
  1295. result = self.store.find(
  1296. Sum(FooValue.value2), Foo.id == FooValue.foo_id)
  1297. result.group_by(Foo.id)
  1298. result.having(Sum(FooValue.value2) == 5)
  1299. self.assertEquals(list(result), [5])
  1300. result = self.store.find(
  1301. Sum(FooValue.value2), Foo.id == FooValue.foo_id)
  1302. result.group_by(Foo.id)
  1303. result.having(Count() == 5)
  1304. self.assertEquals(list(result), [16])
  1305. def test_find_having_without_group_by(self):
  1306. result = self.store.find(FooValue)
  1307. self.assertRaises(FeatureError, result.having, FooValue.value1 == 1)
  1308. def test_find_group_by_multiple_having(self):
  1309. result = self.store.find((Count(), FooValue.value2))
  1310. result.group_by(FooValue.value2)
  1311. result.having(Count() == 2, FooValue.value2 >= 3)
  1312. result.order_by(Count(), FooValue.value2)
  1313. list_result = list(result)
  1314. self.assertEquals(list_result, [(2, 3), (2, 4)])
  1315. def test_find_successive_group_by(self):
  1316. result = self.store.find(Count())
  1317. result.group_by(FooValue.value2)
  1318. result.order_by(Count())
  1319. list_result = list(result)
  1320. self.assertEquals(list_result, [2, 2, 2, 3])
  1321. result.group_by(FooValue.value1)
  1322. list_result = list(result)
  1323. self.assertEquals(list_result, [4, 5])
  1324. def test_find_multiple_group_by(self):
  1325. result = self.store.find(Count())
  1326. result.group_by(FooValue.value2, FooValue.value1)
  1327. result.order_by(Count())
  1328. list_result = list(result)
  1329. self.assertEquals(list_result, [1, 1, 2, 2, 3])
  1330. def test_find_multiple_group_by_with_having(self):
  1331. result = self.store.find((Count(), FooValue.value2))
  1332. result.group_by(FooValue.value2, FooValue.value1).having(Count() == 2)
  1333. result.order_by(Count(), FooValue.value2)
  1334. list_result = list(result)
  1335. self.assertEquals(list_result, [(2, 3), (2, 4)])
  1336. def test_find_group_by_avg(self):
  1337. result = self.store.find((Count(FooValue.id), Sum(FooValue.value1)))
  1338. result.group_by(FooValue.value2)
  1339. self.assertRaises(FeatureError, result.avg, FooValue.value2)
  1340. def test_find_group_by_values(self):
  1341. result = self.store.find(
  1342. (Sum(FooValue.value2), Foo), Foo.id == FooValue.foo_id)
  1343. result.group_by(Foo)
  1344. result.order_by(Foo.title)
  1345. result = list(result.values(Foo.title))
  1346. self.assertEquals(result, [u'Title 20', u'Title 30'])
  1347. def test_find_group_by_union(self):
  1348. result1 = self.store.find(Foo, id=30)
  1349. result2 = self.store.find(Foo, id=10)
  1350. result3 = result1.union(result2)
  1351. self.assertRaises(FeatureError, result3.group_by, Foo.title)
  1352. def test_find_group_by_remove(self):
  1353. result = self.store.find((Count(FooValue.id), Sum(FooValue.value1)))
  1354. result.group_by(FooValue.value2)
  1355. self.assertRaises(FeatureError, result.remove)
  1356. def test_find_group_by_set(self):
  1357. result = self.store.find((Count(FooValue.id), Sum(FooValue.value1)))
  1358. result.group_by(FooValue.value2)
  1359. self.assertRaises(FeatureError, result.set, FooValue.value1 == 1)
  1360. def test_add_commit(self):
  1361. foo = Foo()
  1362. foo.id = 40
  1363. foo.title = u"Title 40"
  1364. self.store.add(foo)
  1365. self.assertEquals(self.get_committed_items(), [
  1366. (10, "Title 30"),
  1367. (20, "Title 20"),
  1368. (30, "Title 10"),
  1369. ])
  1370. self.store.commit()
  1371. self.assertEquals(self.get_committed_items(), [
  1372. (10, "Title 30"),
  1373. (20, "Title 20"),
  1374. (30, "Title 10"),
  1375. (40, "Title 40"),
  1376. ])
  1377. def test_add_rollback_commit(self):
  1378. foo = Foo()
  1379. foo.id = 40
  1380. foo.title = u"Title 40"
  1381. self.store.add(foo)
  1382. self.store.rollback()
  1383. self.assertEquals(self.store.get(Foo, 3), None)
  1384. self.assertEquals(self.get_committed_items(), [
  1385. (10, "Title 30"),
  1386. (20, "Title 20"),
  1387. (30, "Title 10"),
  1388. ])
  1389. self.store.commit()
  1390. self.assertEquals(self.get_committed_items(), [
  1391. (10, "Title 30"),
  1392. (20, "Title 20"),
  1393. (30, "Title 10"),
  1394. ])
  1395. def test_add_get(self):
  1396. foo = Foo()
  1397. foo.id = 40
  1398. foo.title = u"Title 40"
  1399. self.store.add(foo)
  1400. old_foo = foo
  1401. foo = self.store.get(Foo, 40)
  1402. self.assertEquals(foo.id, 40)
  1403. self.assertEquals(foo.title, "Title 40")
  1404. self.assertTrue(foo is old_foo)
  1405. def test_add_find(self):
  1406. foo = Foo()
  1407. foo.id = 40
  1408. foo.title = u"Title 40"
  1409. self.store.add(foo)
  1410. old_foo = foo
  1411. foo = self.store.find(Foo, Foo.id == 40).one()
  1412. self.assertEquals(foo.id, 40)
  1413. self.assertEquals(foo.title, "Title 40")
  1414. self.assertTrue(foo is old_foo)
  1415. def test_add_twice(self):
  1416. foo = Foo()
  1417. self.store.add(foo)
  1418. self.store.add(foo)
  1419. self.assertEquals(Store.of(foo), self.store)
  1420. def test_add_loaded(self):
  1421. foo = self.store.get(Foo, 10)
  1422. self.store.add(foo)
  1423. self.assertEquals(Store.of(foo), self.store)
  1424. def test_add_twice_to_wrong_store(self):
  1425. foo = Foo()
  1426. self.store.add(foo)
  1427. self.assertRaises(WrongStoreError, Store(self.database).add, foo)
  1428. def test_add_checkpoints(self):
  1429. bar = Bar()
  1430. self.store.add(bar)
  1431. bar.id = 400
  1432. bar.title = u"Title 400"
  1433. bar.foo_id = 40
  1434. self.store.flush()
  1435. self.store.execute("UPDATE bar SET title='Title 500' "
  1436. "WHERE id=400")
  1437. bar.foo_id = 400
  1438. # When not checkpointing, this flush will set title again.
  1439. self.store.flush()
  1440. self.store.reload(bar)
  1441. self.assertEquals(bar.title, "Title 500")
  1442. def test_add_completely_undefined(self):
  1443. foo = Foo()
  1444. self.store.add(foo)
  1445. self.store.flush()
  1446. self.assertEquals(type(foo.id), int)
  1447. self.assertEquals(foo.title, u"Default Title")
  1448. def test_remove_commit(self):
  1449. foo = self.store.get(Foo, 20)
  1450. self.store.remove(foo)
  1451. self.assertEquals(Store.of(foo), self.store)
  1452. self.store.flush()
  1453. self.assertEquals(Store.of(foo), None)
  1454. self.assertEquals(self.get_items(), [
  1455. (10, "Title 30"),
  1456. (30, "Title 10"),
  1457. ])
  1458. self.assertEquals(self.get_committed_items(), [
  1459. (10, "Title 30"),
  1460. (20, "Title 20"),
  1461. (30, "Title 10"),
  1462. ])
  1463. self.store.commit()
  1464. self.assertEquals(Store.of(foo), None)
  1465. self.assertEquals(self.get_committed_items(), [
  1466. (10, "Title 30"),
  1467. (30, "Title 10"),
  1468. ])
  1469. def test_remove_rollback_update(self):
  1470. foo = self.store.get(Foo, 20)
  1471. self.store.remove(foo)
  1472. self.store.rollback()
  1473. foo.title = u"Title 200"
  1474. self.store.flush()
  1475. self.assertEquals(self.get_items(), [
  1476. (10, "Title 30"),
  1477. (20, "Title 200"),
  1478. (30, "Title 10"),
  1479. ])
  1480. def test_remove_flush_rollback_update(self):
  1481. foo = self.store.get(Foo, 20)
  1482. self.store.remove(foo)
  1483. self.store.flush()
  1484. self.store.rollback()
  1485. foo.title = u"Title 200"
  1486. self.store.flush()
  1487. self.assertEquals(self.get_items(), [
  1488. (10, "Title 30"),
  1489. (20, "Title 20"),
  1490. (30, "Title 10"),
  1491. ])
  1492. def test_remove_add_update(self):
  1493. foo = self.store.get(Foo, 20)
  1494. self.store.remove(foo)
  1495. self.store.add(foo)
  1496. foo.title = u"Title 200"
  1497. self.store.flush()
  1498. self.assertEquals(self.get_items(), [
  1499. (10, "Title 30"),
  1500. (20, "Title 200"),
  1501. (30, "Title 10"),
  1502. ])
  1503. def test_remove_flush_add_update(self):
  1504. foo = self.store.get(Foo, 20)
  1505. self.store.remove(foo)
  1506. self.store.flush()
  1507. self.store.add(foo)
  1508. foo.title = u"Title 200"
  1509. self.store.flush()
  1510. self.assertEquals(self.get_items(), [
  1511. (10, "Title 30"),
  1512. (20, "Title 200"),
  1513. (30, "Title 10"),
  1514. ])
  1515. def test_remove_twice(self):
  1516. foo = self.store.get(Foo, 10)
  1517. self.store.remove(foo)
  1518. self.store.remove(foo)
  1519. def test_remove_unknown(self):
  1520. foo = Foo()
  1521. self.assertRaises(WrongStoreError, self.store.remove, foo)
  1522. def test_remove_from_wrong_store(self):
  1523. foo = self.store.get(Foo, 20)
  1524. self.assertRaises(WrongStoreError, Store(self.database).remove, foo)
  1525. def test_wb_remove_flush_update_isnt_dirty(self):
  1526. foo = self.store.get(Foo, 20)
  1527. obj_info = get_obj_info(foo)
  1528. self.store.remove(foo)
  1529. self.store.flush()
  1530. foo.title = u"Title 200"
  1531. self.assertTrue(obj_info not in self.store._dirty)
  1532. def test_wb_remove_rollback_isnt_dirty(self):
  1533. foo = self.store.get(Foo, 20)
  1534. obj_info = get_obj_info(foo)
  1535. self.store.remove(foo)
  1536. self.store.rollback()
  1537. self.assertTrue(obj_info not in self.store._dirty)
  1538. def test_wb_remove_flush_rollback_isnt_dirty(self):
  1539. foo = self.store.get(Foo, 20)
  1540. obj_info = get_obj_info(foo)
  1541. self.store.remove(foo)
  1542. self.store.flush()
  1543. self.store.rollback()
  1544. self.assertTrue(obj_info not in self.store._dirty)
  1545. def test_add_rollback_not_in_store(self):
  1546. foo = Foo()
  1547. foo.id = 40
  1548. foo.title = u"Title 40"
  1549. self.store.add(foo)
  1550. self.store.rollback()
  1551. self.assertEquals(Store.of(foo), None)
  1552. def test_update_flush_commit(self):
  1553. foo = self.store.get(Foo, 20)
  1554. foo.title = u"Title 200"
  1555. self.assertEquals(self.get_items(), [
  1556. (10, "Title 30"),
  1557. (20, "Title 20"),
  1558. (30, "Title 10"),
  1559. ])
  1560. self.assertEquals(self.get_committed_items(), [
  1561. (10, "Title 30"),
  1562. (20, "Title 20"),
  1563. (30, "Title 10"),
  1564. ])
  1565. self.store.flush()
  1566. self.assertEquals(self.get_items(), [
  1567. (10, "Title 30"),
  1568. (20, "Title 200"),
  1569. (30, "Title 10"),
  1570. ])
  1571. self.assertEquals(self.get_committed_items(), [
  1572. (10, "Title 30"),
  1573. (20, "Title 20"),
  1574. (30, "Title 10"),
  1575. ])
  1576. self.store.commit()
  1577. self.assertEquals(self.get_committed_items(), [
  1578. (10, "Title 30"),
  1579. (20, "Title 200"),
  1580. (30, "Title 10"),
  1581. ])
  1582. def test_update_flush_reload_rollback(self):
  1583. foo = self.store.get(Foo, 20)
  1584. foo.title = u"Title 200"
  1585. self.store.flush()
  1586. self.store.reload(foo)
  1587. self.store.rollback()
  1588. self.assertEquals(foo.title, "Title 20")
  1589. def test_update_commit(self):
  1590. foo = self.store.get(Foo, 20)
  1591. foo.title = u"Title 200"
  1592. self.store.commit()
  1593. self.assertEquals(self.get_committed_items(), [
  1594. (10, "Title 30"),
  1595. (20, "Title 200"),
  1596. (30, "Title 10"),
  1597. ])
  1598. def test_update_commit_twice(self):
  1599. foo = self.store.get(Foo, 20)
  1600. foo.title = u"Title 200"
  1601. self.store.commit()
  1602. foo.title = u"Title 2000"
  1603. self.store.commit()
  1604. self.assertEquals(self.get_committed_items(), [
  1605. (10, "Title 30"),
  1606. (20, "Title 2000"),
  1607. (30, "Title 10"),
  1608. ])
  1609. def test_update_checkpoints(self):
  1610. bar = self.store.get(Bar, 200)
  1611. bar.title = u"Title 400"
  1612. self.store.flush()
  1613. self.store.execute("UPDATE bar SET title='Title 500' "
  1614. "WHERE id=200")
  1615. bar.foo_id = 40
  1616. # When not checkpointing, this flush will set title again.
  1617. self.store.flush()
  1618. self.store.reload(bar)
  1619. self.assertEquals(bar.title, "Title 500")
  1620. def test_update_primary_key(self):
  1621. foo = self.store.get(Foo, 20)
  1622. foo.id = 25
  1623. self.store.commit()
  1624. self.assertEquals(self.get_committed_items(), [
  1625. (10, "Title 30"),
  1626. (25, "Title 20"),
  1627. (30, "Title 10"),
  1628. ])
  1629. # Update twice to see if the notion of primary key for the
  1630. # existent object was updated as well.
  1631. foo.id = 27
  1632. self.store.commit()
  1633. self.assertEquals(self.get_committed_items(), [
  1634. (10, "Title 30"),
  1635. (27, "Title 20"),
  1636. (30, "Title 10"),
  1637. ])
  1638. # Ensure only the right ones are there.
  1639. self.assertTrue(self.store.get(Foo, 27) is foo)
  1640. self.assertTrue(self.store.get(Foo, 25) is None)
  1641. self.assertTrue(self.store.get(Foo, 20) is None)
  1642. def test_update_primary_key_exchange(self):
  1643. foo1 = self.store.get(Foo, 10)
  1644. foo2 = self.store.get(Foo, 30)
  1645. foo1.id = 40
  1646. self.store.flush()
  1647. foo2.id = 10
  1648. self.store.flush()
  1649. foo1.id = 30
  1650. self.assertTrue(self.store.get(Foo, 30) is foo1)
  1651. self.assertTrue(self.store.get(Foo, 10) is foo2)
  1652. self.store.commit()
  1653. self.assertEquals(self.get_committed_items(), [
  1654. (10, "Title 10"),
  1655. (20, "Title 20"),
  1656. (30, "Title 30"),
  1657. ])
  1658. def test_wb_update_not_dirty_after_flush(self):
  1659. foo = self.store.get(Foo, 20)
  1660. foo.title = u"Title 200"
  1661. self.store.flush()
  1662. # If changes get committed even with the notification disabled,
  1663. # it means the dirty flag isn't being cleared.
  1664. self.store._disable_change_notification(get_obj_info(foo))
  1665. foo.title = u"Title 2000"
  1666. self.store.flush()
  1667. self.assertEquals(self.get_items(), [
  1668. (10, "Title 30"),
  1669. (20, "Title 200"),
  1670. (30, "Title 10"),
  1671. ])
  1672. def test_update_find(self):
  1673. foo = self.store.get(Foo, 20)
  1674. foo.title = u"Title 200"
  1675. result = self.store.find(Foo, Foo.title == u"Title 200")
  1676. self.assertTrue(result.one() is foo)
  1677. def test_update_get(self):
  1678. foo = self.store.get(Foo, 20)
  1679. foo.id = 200
  1680. self.assertTrue(self.store.get(Foo, 200) is foo)
  1681. def test_add_update(self):
  1682. foo = Foo()
  1683. foo.id = 40
  1684. foo.title = u"Title 40"
  1685. self.store.add(foo)
  1686. foo.title = u"Title 400"
  1687. self.store.flush()
  1688. self.assertEquals(self.get_items(), [
  1689. (10, "Title 30"),
  1690. (20, "Title 20"),
  1691. (30, "Title 10"),
  1692. (40, "Title 400"),
  1693. ])
  1694. def test_add_remove_add(self):
  1695. foo = Foo()
  1696. foo.id = 40
  1697. foo.title = u"Title 40"
  1698. self.store.add(foo)
  1699. self.store.remove(foo)
  1700. self.assertEquals(Store.of(foo), None)
  1701. foo.title = u"Title 400"
  1702. self.store.add(foo)
  1703. foo.id = 400
  1704. self.store.commit()
  1705. self.assertEquals(Store.of(foo), self.store)
  1706. self.assertEquals(self.get_items(), [
  1707. (10, "Title 30"),
  1708. (20, "Title 20"),
  1709. (30, "Title 10"),
  1710. (400, "Title 400"),
  1711. ])
  1712. self.assertTrue(self.store.get(Foo, 400) is foo)
  1713. def test_wb_add_remove_add(self):
  1714. foo = Foo()
  1715. obj_info = get_obj_info(foo)
  1716. self.store.add(foo)
  1717. self.assertTrue(obj_info in self.store._dirty)
  1718. self.store.remove(foo)
  1719. self.assertTrue(obj_info not in self.store._dirty)
  1720. self.store.add(foo)
  1721. self.assertTrue(obj_info in self.store._dirty)
  1722. self.assertTrue(Store.of(foo) is self.store)
  1723. def test_wb_update_remove_add(self):
  1724. foo = self.store.get(Foo, 20)
  1725. foo.title = u"Title 200"
  1726. obj_info = get_obj_info(foo)
  1727. self.store.remove(foo)
  1728. self.store.add(foo)
  1729. self.assertTrue(obj_info in self.store._dirty)
  1730. def test_commit_autoreloads(self):
  1731. foo = self.store.get(Foo, 20)
  1732. self.assertEquals(foo.title, "Title 20")
  1733. self.store.execute("UPDATE foo SET title='New Title' WHERE id=20")
  1734. self.assertEquals(foo.title, "Title 20")
  1735. self.store.commit()
  1736. self.assertEquals(foo.title, "New Title")
  1737. def test_commit_invalidates(self):
  1738. foo = self.store.get(Foo, 20)
  1739. self.assertTrue(foo)
  1740. self.store.execute("DELETE FROM foo WHERE id=20")
  1741. self.assertEquals(self.store.get(Foo, 20), foo)
  1742. self.store.commit()
  1743. self.assertEquals(self.store.get(Foo, 20), None)
  1744. def test_rollback_autoreloads(self):
  1745. foo = self.store.get(Foo, 20)
  1746. self.assertEquals(foo.title, "Title 20")
  1747. self.store.rollback()
  1748. self.store.execute("UPDATE foo SET title='New Title' WHERE id=20")
  1749. self.assertEquals(foo.title, "New Title")
  1750. def test_rollback_invalidates(self):
  1751. foo = self.store.get(Foo, 20)
  1752. self.assertTrue(foo)
  1753. self.assertEquals(self.store.get(Foo, 20), foo)
  1754. self.store.rollback()
  1755. self.store.execute("DELETE FROM foo WHERE id=20")
  1756. self.assertEquals(self.store.get(Foo, 20), None)
  1757. def test_sub_class(self):
  1758. class SubFoo(Foo):
  1759. id = Float(primary=True)
  1760. foo1 = self.store.get(Foo, 20)
  1761. foo2 = self.store.get(SubFoo, 20)
  1762. self.assertEquals(foo1.id, 20)
  1763. self.assertEquals(foo2.id, 20)
  1764. self.assertEquals(type(foo1.id), int)
  1765. self.assertEquals(type(foo2.id), float)
  1766. def test_join(self):
  1767. class Bar(object):
  1768. __storm_table__ = "bar"
  1769. id = Int(primary=True)
  1770. title = Unicode()
  1771. bar = Bar()
  1772. bar.id = 40
  1773. bar.title = u"Title 20"
  1774. self.store.add(bar)
  1775. # Add anbar object with the same title to ensure DISTINCT
  1776. # is in place.
  1777. bar = Bar()
  1778. bar.id = 400
  1779. bar.title = u"Title 20"
  1780. self.store.add(bar)
  1781. result = self.store.find(Foo, Foo.title == Bar.title)
  1782. self.assertEquals([(foo.id, foo.title) for foo in result], [
  1783. (20, "Title 20"),
  1784. (20, "Title 20"),
  1785. ])
  1786. def test_join_distinct(self):
  1787. class Bar(object):
  1788. __storm_table__ = "bar"
  1789. id = Int(primary=True)
  1790. title = Unicode()
  1791. bar = Bar()
  1792. bar.id = 40
  1793. bar.title = u"Title 20"
  1794. self.store.add(bar)
  1795. # Add a bar object with the same title to ensure DISTINCT
  1796. # is in place.
  1797. bar = Bar()
  1798. bar.id = 400
  1799. bar.title = u"Title 20"
  1800. self.store.add(bar)
  1801. result = self.store.find(Foo, Foo.title == Bar.title)
  1802. result.config(distinct=True)
  1803. # Make sure that it won't unset it, and that it's returning itself.
  1804. config = result.config()
  1805. self.assertEquals([(foo.id, foo.title) for foo in result], [
  1806. (20, "Title 20"),
  1807. ])
  1808. def test_sub_select(self):
  1809. foo = self.store.find(Foo, Foo.id == Select(SQL("20"))).one()
  1810. self.assertTrue(foo)
  1811. self.assertEquals(foo.id, 20)
  1812. self.assertEquals(foo.title, "Title 20")
  1813. def test_cache_has_improper_object(self):
  1814. foo = self.store.get(Foo, 20)
  1815. self.store.remove(foo)
  1816. self.store.commit()
  1817. self.store.execute("INSERT INTO foo VALUES (20, 'Title 20')")
  1818. self.assertTrue(self.store.get(Foo, 20) is not foo)
  1819. def test_cache_has_improper_object_readded(self):
  1820. foo = self.store.get(Foo, 20)
  1821. self.store.remove(foo)
  1822. self.store.flush()
  1823. old_foo = foo # Keep a reference.
  1824. foo = Foo()
  1825. foo.id = 20
  1826. foo.title = u"Readded"
  1827. self.store.add(foo)
  1828. self.store.commit()
  1829. self.assertTrue(self.store.get(Foo, 20) is foo)
  1830. def test_loaded_hook(self):
  1831. loaded = []
  1832. class MyFoo(Foo):
  1833. def __init__(self):
  1834. loaded.append("NO!")
  1835. def __storm_loaded__(self):
  1836. loaded.append((self.id, self.title))
  1837. self.title = u"Title 200"
  1838. self.some_attribute = 1
  1839. foo = self.store.get(MyFoo, 20)
  1840. self.assertEquals(loaded, [(20, "Title 20")])
  1841. self.assertEquals(foo.title, "Title 200")
  1842. self.assertEquals(foo.some_attribute, 1)
  1843. foo.some_attribute = 2
  1844. self.store.flush()
  1845. self.assertEquals(self.get_items(), [
  1846. (10, "Title 30"),
  1847. (20, "Title 200"),
  1848. (30, "Title 10"),
  1849. ])
  1850. self.store.rollback()
  1851. self.assertEquals(foo.title, "Title 20")
  1852. self.assertEquals(foo.some_attribute, 2)
  1853. def test_flush_hook(self):
  1854. class MyFoo(Foo):
  1855. counter = 0
  1856. def __storm_pre_flush__(self):
  1857. if self.counter == 0:
  1858. self.title = u"Flushing: %s" % self.title
  1859. self.counter += 1
  1860. foo = self.store.get(MyFoo, 20)
  1861. self.assertEquals(foo.title, "Title 20")
  1862. self.store.flush()
  1863. self.assertEquals(foo.title, "Title 20") # It wasn't dirty.
  1864. foo.title = u"Something"
  1865. self.store.flush()
  1866. self.assertEquals(foo.title, "Flushing: Something")
  1867. # It got in the database, because it was flushed *twice* (the
  1868. # title was changed after flushed, and thus the object got dirty
  1869. # again).
  1870. self.assertEquals(self.get_items(), [
  1871. (10, "Title 30"),
  1872. (20, "Flushing: Something"),
  1873. (30, "Title 10"),
  1874. ])
  1875. # This shouldn't do anything, because the object is clean again.
  1876. foo.counter = 0
  1877. self.store.flush()
  1878. self.assertEquals(foo.title, "Flushing: Something")
  1879. def test_flush_hook_all(self):
  1880. class MyFoo(Foo):
  1881. def __storm_pre_flush__(self):
  1882. other = [foo1, foo2][foo1 is self]
  1883. other.title = u"Changed in hook: " + other.title
  1884. foo1 = self.store.get(MyFoo, 10)
  1885. foo2 = self.store.get(MyFoo, 20)
  1886. foo1.title = u"Changed"
  1887. self.store.flush()
  1888. self.assertEquals(foo1.title, "Changed in hook: Changed")
  1889. self.assertEquals(foo2.title, "Changed in hook: Title 20")
  1890. def test_flushed_hook(self):
  1891. class MyFoo(Foo):
  1892. done = False
  1893. def __storm_flushed__(self):
  1894. if not self.done:
  1895. self.done = True
  1896. self.title = u"Flushed: %s" % self.title
  1897. foo = self.store.get(MyFoo, 20)
  1898. self.assertEquals(foo.title, "Title 20")
  1899. self.store.flush()
  1900. self.assertEquals(foo.title, "Title 20") # It wasn't dirty.
  1901. foo.title = u"Something"
  1902. self.store.flush()
  1903. self.assertEquals(foo.title, "Flushed: Something")
  1904. # It got in the database, because it was flushed *twice* (the
  1905. # title was changed after flushed, and thus the object got dirty
  1906. # again).
  1907. self.assertEquals(self.get_items(), [
  1908. (10, "Title 30"),
  1909. (20, "Flushed: Something"),
  1910. (30, "Title 10"),
  1911. ])
  1912. # This shouldn't do anything, because the object is clean again.
  1913. foo.done = False
  1914. self.store.flush()
  1915. self.assertEquals(foo.title, "Flushed: Something")
  1916. def test_retrieve_default_primary_key(self):
  1917. foo = Foo()
  1918. foo.title = u"Title 40"
  1919. self.store.add(foo)
  1920. self.store.flush()
  1921. self.assertNotEquals(foo.id, None)
  1922. self.assertTrue(self.store.get(Foo, foo.id) is foo)
  1923. def test_retrieve_default_value(self):
  1924. foo = Foo()
  1925. foo.id = 40
  1926. self.store.add(foo)
  1927. self.store.flush()
  1928. self.assertEquals(foo.title, "Default Title")
  1929. def test_retrieve_null_when_no_default(self):
  1930. bar = Bar()
  1931. bar.id = 400
  1932. self.store.add(bar)
  1933. self.store.flush()
  1934. self.assertEquals(bar.title, None)
  1935. def test_wb_remove_prop_not_dirty(self):
  1936. foo = self.store.get(Foo, 20)
  1937. obj_info = get_obj_info(foo)
  1938. del foo.title
  1939. self.assertTrue(obj_info not in self.store._dirty)
  1940. def test_flush_with_removed_prop(self):
  1941. foo = self.store.get(Foo, 20)
  1942. del foo.title
  1943. self.store.flush()
  1944. self.assertEquals(self.get_items(), [
  1945. (10, "Title 30"),
  1946. (20, "Title 20"),
  1947. (30, "Title 10"),
  1948. ])
  1949. def test_flush_with_removed_prop_forced_dirty(self):
  1950. foo = self.store.get(Foo, 20)
  1951. del foo.title
  1952. foo.id = 40
  1953. foo.id = 20
  1954. self.store.flush()
  1955. self.assertEquals(self.get_items(), [
  1956. (10, "Title 30"),
  1957. (20, "Title 20"),
  1958. (30, "Title 10"),
  1959. ])
  1960. def test_flush_with_removed_prop_really_dirty(self):
  1961. foo = self.store.get(Foo, 20)
  1962. del foo.title
  1963. foo.id = 25
  1964. self.store.flush()
  1965. self.assertEquals(self.get_items(), [
  1966. (10, "Title 30"),
  1967. (25, "Title 20"),
  1968. (30, "Title 10"),
  1969. ])
  1970. def test_wb_block_implicit_flushes(self):
  1971. # Make sure calling store.flush() will fail.
  1972. def flush():
  1973. raise RuntimeError("Flush called")
  1974. self.store.flush = flush
  1975. # The following operations do not call flush.
  1976. self.store.block_implicit_flushes()
  1977. foo = self.store.get(Foo, 20)
  1978. foo = self.store.find(Foo, Foo.id == 20).one()
  1979. self.store.execute("SELECT title FROM foo WHERE id = 20")
  1980. self.store.unblock_implicit_flushes()
  1981. self.assertRaises(RuntimeError, self.store.get, Foo, 20)
  1982. def test_wb_block_implicit_flushes_is_recursive(self):
  1983. # Make sure calling store.flush() will fail.
  1984. def flush():
  1985. raise RuntimeError("Flush called")
  1986. self.store.flush = flush
  1987. self.store.block_implicit_flushes()
  1988. self.store.block_implicit_flushes()
  1989. self.store.unblock_implicit_flushes()
  1990. # implicit flushes are still blocked, until unblock() is called again.
  1991. foo = self.store.get(Foo, 20)
  1992. self.store.unblock_implicit_flushes()
  1993. self.assertRaises(RuntimeError, self.store.get, Foo, 20)
  1994. def test_block_access(self):
  1995. """Access to the store is blocked by block_access()."""
  1996. # The set_blocked() method blocks access to the connection.
  1997. self.store.block_access()
  1998. self.assertRaises(ConnectionBlockedError,
  1999. self.store.execute, "SELECT 1")
  2000. self.assertRaises(ConnectionBlockedError, self.store.commit)
  2001. # The rollback method is not blocked.
  2002. self.store.rollback()
  2003. self.store.unblock_access()
  2004. self.store.execute("SELECT 1")
  2005. def test_reload(self):
  2006. foo = self.store.get(Foo, 20)
  2007. self.store.execute("UPDATE foo SET title='Title 40' WHERE id=20")
  2008. self.assertEquals(foo.title, "Title 20")
  2009. self.store.reload(foo)
  2010. self.assertEquals(foo.title, "Title 40")
  2011. def test_reload_not_changed(self):
  2012. foo = self.store.get(Foo, 20)
  2013. self.store.execute("UPDATE foo SET title='Title 40' WHERE id=20")
  2014. self.store.reload(foo)
  2015. for variable in get_obj_info(foo).variables.values():
  2016. self.assertFalse(variable.has_changed())
  2017. def test_reload_new(self):
  2018. foo = Foo()
  2019. foo.id = 40
  2020. foo.title = u"Title 40"
  2021. self.assertRaises(WrongStoreError, self.store.reload, foo)
  2022. def test_reload_new_unflushed(self):
  2023. foo = Foo()
  2024. foo.id = 40
  2025. foo.title = u"Title 40"
  2026. self.store.add(foo)
  2027. self.assertRaises(NotFlushedError, self.store.reload, foo)
  2028. def test_reload_removed(self):
  2029. foo = self.store.get(Foo, 20)
  2030. self.store.remove(foo)
  2031. self.store.flush()
  2032. self.assertRaises(WrongStoreError, self.store.reload, foo)
  2033. def test_reload_unknown(self):
  2034. foo = self.store.get(Foo, 20)
  2035. store = self.create_store()
  2036. self.assertRaises(WrongStoreError, store.reload, foo)
  2037. def test_wb_reload_not_dirty(self):
  2038. foo = self.store.get(Foo, 20)
  2039. obj_info = get_obj_info(foo)
  2040. foo.title = u"Title 40"
  2041. self.store.reload(foo)
  2042. self.assertTrue(obj_info not in self.store._dirty)
  2043. def test_find_set_empty(self):
  2044. self.store.find(Foo, title=u"Title 20").set()
  2045. foo = self.store.get(Foo, 20)
  2046. self.assertEquals(foo.title, "Title 20")
  2047. def test_find_set(self):
  2048. self.store.find(Foo, title=u"Title 20").set(title=u"Title 40")
  2049. foo = self.store.get(Foo, 20)
  2050. self.assertEquals(foo.title, "Title 40")
  2051. def test_find_set_with_func_expr(self):
  2052. self.store.find(Foo, title=u"Title 20").set(title=Lower(u"Title 40"))
  2053. foo = self.store.get(Foo, 20)
  2054. self.assertEquals(foo.title, "title 40")
  2055. def test_find_set_equality_with_func_expr(self):
  2056. self.store.find(Foo, title=u"Title 20").set(
  2057. Foo.title == Lower(u"Title 40"))
  2058. foo = self.store.get(Foo, 20)
  2059. self.assertEquals(foo.title, "title 40")
  2060. def test_find_set_column(self):
  2061. self.store.find(Bar, title=u"Title 200").set(foo_id=Bar.id)
  2062. bar = self.store.get(Bar, 200)
  2063. self.assertEquals(bar.foo_id, 200)
  2064. def test_find_set_expr(self):
  2065. self.store.find(Foo, title=u"Title 20").set(Foo.title == u"Title 40")
  2066. foo = self.store.get(Foo, 20)
  2067. self.assertEquals(foo.title, "Title 40")
  2068. def test_find_set_none(self):
  2069. self.store.find(Foo, title=u"Title 20").set(title=None)
  2070. foo = self.store.get(Foo, 20)
  2071. self.assertEquals(foo.title, None)
  2072. def test_find_set_expr_column(self):
  2073. self.store.find(Bar, id=200).set(Bar.foo_id == Bar.id)
  2074. bar = self.store.get(Bar, 200)
  2075. self.assertEquals(bar.id, 200)
  2076. self.assertEquals(bar.foo_id, 200)
  2077. def test_find_set_on_cached(self):
  2078. foo1 = self.store.get(Foo, 20)
  2079. foo2 = self.store.get(Foo, 30)
  2080. self.store.find(Foo, id=20).set(id=40)
  2081. self.assertEquals(foo1.id, 40)
  2082. self.assertEquals(foo2.id, 30)
  2083. def test_find_set_expr_on_cached(self):
  2084. bar = self.store.get(Bar, 200)
  2085. self.store.find(Bar, id=200).set(Bar.foo_id == Bar.id)
  2086. self.assertEquals(bar.id, 200)
  2087. self.assertEquals(bar.foo_id, 200)
  2088. def test_find_set_none_on_cached(self):
  2089. foo = self.store.get(Foo, 20)
  2090. self.store.find(Foo, title=u"Title 20").set(title=None)
  2091. self.assertEquals(foo.title, None)
  2092. def test_find_set_on_cached_but_removed(self):
  2093. foo1 = self.store.get(Foo, 20)
  2094. foo2 = self.store.get(Foo, 30)
  2095. self.store.remove(foo1)
  2096. self.store.find(Foo, id=20).set(id=40)
  2097. self.assertEquals(foo1.id, 20)
  2098. self.assertEquals(foo2.id, 30)
  2099. def test_find_set_on_cached_unsupported_python_expr(self):
  2100. foo1 = self.store.get(Foo, 20)
  2101. foo2 = self.store.get(Foo, 30)
  2102. self.store.find(
  2103. Foo, Foo.id == Select(SQL("20"))).set(title=u"Title 40")
  2104. self.assertEquals(foo1.title, "Title 40")
  2105. self.assertEquals(foo2.title, "Title 10")
  2106. def test_find_set_expr_unsupported(self):
  2107. result = self.store.find(Foo, title=u"Title 20")
  2108. self.assertRaises(FeatureError, result.set, Foo.title > u"Title 40")
  2109. def test_find_set_expr_unsupported_without_column(self):
  2110. result = self.store.find(Foo, title=u"Title 20")
  2111. self.assertRaises(FeatureError, result.set,
  2112. Eq(object(), IntVariable(1)))
  2113. def test_find_set_expr_unsupported_without_expr_or_variable(self):
  2114. result = self.store.find(Foo, title=u"Title 20")
  2115. self.assertRaises(FeatureError, result.set, Eq(Foo.id, object()))
  2116. def test_find_set_expr_unsupported_autoreloads(self):
  2117. bar1 = self.store.get(Bar, 200)
  2118. bar2 = self.store.get(Bar, 300)
  2119. self.store.find(Bar, id=Select(SQL("200"))).set(title=u"Title 400")
  2120. bar1_vars = get_obj_info(bar1).variables
  2121. bar2_vars = get_obj_info(bar2).variables
  2122. self.assertEquals(bar1_vars[Bar.title].get_lazy(), AutoReload)
  2123. self.assertEquals(bar2_vars[Bar.title].get_lazy(), AutoReload)
  2124. self.assertEquals(bar1_vars[Bar.foo_id].get_lazy(), None)
  2125. self.assertEquals(bar2_vars[Bar.foo_id].get_lazy(), None)
  2126. self.assertEquals(bar1.title, "Title 400")
  2127. self.assertEquals(bar2.title, "Title 100")
  2128. def test_find_set_expr_unsupported_mixed_autoreloads(self):
  2129. # For an expression that does not compile (eg:
  2130. # ResultSet.cached() raises a CompileError), while setting
  2131. # cached entries' columns to AutoReload, if objects of
  2132. # different types could be found in the cache then a KeyError
  2133. # would happen if some object did not have a matching
  2134. # column. See Bug #328603 for more info.
  2135. foo1 = self.store.get(Foo, 20)
  2136. bar1 = self.store.get(Bar, 200)
  2137. self.store.find(Bar, id=Select(SQL("200"))).set(title=u"Title 400")
  2138. foo1_vars = get_obj_info(foo1).variables
  2139. bar1_vars = get_obj_info(bar1).variables
  2140. self.assertNotEquals(foo1_vars[Foo.title].get_lazy(), AutoReload)
  2141. self.assertEquals(bar1_vars[Bar.title].get_lazy(), AutoReload)
  2142. self.assertEquals(bar1_vars[Bar.foo_id].get_lazy(), None)
  2143. self.assertEquals(foo1.title, "Title 20")
  2144. self.assertEquals(bar1.title, "Title 400")
  2145. def test_find_set_autoreloads_with_func_expr(self):
  2146. # In the process of fixing this bug, we've temporarily
  2147. # introduced another bug: the expression would be called
  2148. # twice. We've used an expression that increments the value by
  2149. # one here to see if that case is triggered. In the buggy
  2150. # bugfix, the value would end up being incremented by two due
  2151. # to misfiring two updates.
  2152. foo1 = self.store.get(FooValue, 1)
  2153. self.assertEquals(foo1.value1, 2)
  2154. self.store.find(FooValue, id=1).set(value1=SQL("value1 + 1"))
  2155. foo1_vars = get_obj_info(foo1).variables
  2156. self.assertEquals(foo1_vars[FooValue.value1].get_lazy(), AutoReload)
  2157. self.assertEquals(foo1.value1, 3)
  2158. def test_find_set_equality_autoreloads_with_func_expr(self):
  2159. foo1 = self.store.get(FooValue, 1)
  2160. self.assertEquals(foo1.value1, 2)
  2161. self.store.find(FooValue, id=1).set(
  2162. FooValue.value1 == SQL("value1 + 1"))
  2163. foo1_vars = get_obj_info(foo1).variables
  2164. self.assertEquals(foo1_vars[FooValue.value1].get_lazy(), AutoReload)
  2165. self.assertEquals(foo1.value1, 3)
  2166. def test_wb_find_set_checkpoints(self):
  2167. bar = self.store.get(Bar, 200)
  2168. self.store.find(Bar, id=200).set(title=u"Title 400")
  2169. self.store._connection.execute("UPDATE bar SET "
  2170. "title='Title 500' "
  2171. "WHERE id=200")
  2172. # When not checkpointing, this flush will set title again.
  2173. self.store.flush()
  2174. self.store.reload(bar)
  2175. self.assertEquals(bar.title, "Title 500")
  2176. def test_find_set_with_info_alive_and_object_dead(self):
  2177. # Disable the cache, which holds strong references.
  2178. self.get_cache(self.store).set_size(0)
  2179. foo = self.store.get(Foo, 20)
  2180. foo.tainted = True
  2181. obj_info = get_obj_info(foo)
  2182. del foo
  2183. gc.collect()
  2184. self.store.find(Foo, title=u"Title 20").set(title=u"Title 40")
  2185. foo = self.store.get(Foo, 20)
  2186. self.assertFalse(hasattr(foo, "tainted"))
  2187. self.assertEquals(foo.title, "Title 40")
  2188. def test_reference(self):
  2189. bar = self.store.get(Bar, 100)
  2190. self.assertTrue(bar.foo)
  2191. self.assertEquals(bar.foo.title, "Title 30")
  2192. def test_reference_explicitly_with_wrapper(self):
  2193. bar = self.store.get(Bar, 100)
  2194. foo = Bar.foo.__get__(Wrapper(bar))
  2195. self.assertTrue(foo)
  2196. self.assertEquals(foo.title, "Title 30")
  2197. def test_reference_break_on_local_diverged(self):
  2198. bar = self.store.get(Bar, 100)
  2199. self.assertTrue(bar.foo)
  2200. bar.foo_id = 40
  2201. self.assertEquals(bar.foo, None)
  2202. def test_reference_break_on_remote_diverged(self):
  2203. bar = self.store.get(Bar, 100)
  2204. bar.foo.id = 40
  2205. self.assertEquals(bar.foo, None)
  2206. def test_reference_break_on_local_diverged_by_lazy(self):
  2207. bar = self.store.get(Bar, 100)
  2208. self.assertEquals(bar.foo.id, 10)
  2209. bar.foo_id = SQL("20")
  2210. self.assertEquals(bar.foo.id, 20)
  2211. def test_reference_remote_leak_on_flush_with_changed(self):
  2212. """
  2213. "changed" events only hold weak references to remote infos object, thus
  2214. not creating a leak when unhooked.
  2215. """
  2216. self.get_cache(self.store).set_size(0)
  2217. bar = self.store.get(Bar, 100)
  2218. bar.foo.title = u"Changed title"
  2219. bar_ref = weakref.ref(get_obj_info(bar))
  2220. foo = bar.foo
  2221. del bar
  2222. self.store.flush()
  2223. gc.collect()
  2224. self.assertEquals(bar_ref(), None)
  2225. def test_reference_remote_leak_on_flush_with_removed(self):
  2226. """
  2227. "removed" events only hold weak references to remote infos objects,
  2228. thus not creating a leak when unhooked.
  2229. """
  2230. self.get_cache(self.store).set_size(0)
  2231. class MyFoo(Foo):
  2232. bar = Reference(Foo.id, Bar.foo_id, on_remote=True)
  2233. foo = self.store.get(MyFoo, 10)
  2234. foo.bar.title = u"Changed title"
  2235. foo_ref = weakref.ref(get_obj_info(foo))
  2236. bar = foo.bar
  2237. del foo
  2238. self.store.flush()
  2239. gc.collect()
  2240. self.assertEquals(foo_ref(), None)
  2241. def test_reference_break_on_remote_diverged_by_lazy(self):
  2242. class MyBar(Bar):
  2243. pass
  2244. MyBar.foo = Reference(MyBar.title, Foo.title)
  2245. bar = self.store.get(MyBar, 100)
  2246. bar.title = u"Title 30"
  2247. self.store.flush()
  2248. self.assertEquals(bar.foo.id, 10)
  2249. bar.foo.title = SQL("'Title 40'")
  2250. self.assertEquals(bar.foo, None)
  2251. self.assertEquals(self.store.find(Foo, title=u"Title 30").one(), None)
  2252. self.assertEquals(self.store.get(Foo, 10).title, u"Title 40")
  2253. def test_reference_on_non_primary_key(self):
  2254. self.store.execute("INSERT INTO bar VALUES (400, 40, 'Title 30')")
  2255. class MyBar(Bar):
  2256. foo = Reference(Bar.title, Foo.title)
  2257. bar = self.store.get(Bar, 400)
  2258. self.assertEquals(bar.title, "Title 30")
  2259. self.assertEquals(bar.foo, None)
  2260. mybar = self.store.get(MyBar, 400)
  2261. self.assertEquals(mybar.title, "Title 30")
  2262. self.assertNotEquals(mybar.foo, None)
  2263. self.assertEquals(mybar.foo.id, 10)
  2264. self.assertEquals(mybar.foo.title, "Title 30")
  2265. def test_new_reference(self):
  2266. bar = Bar()
  2267. bar.id = 400
  2268. bar.title = u"Title 400"
  2269. bar.foo_id = 10
  2270. self.assertEquals(bar.foo, None)
  2271. self.store.add(bar)
  2272. self.assertTrue(bar.foo)
  2273. self.assertEquals(bar.foo.title, "Title 30")
  2274. def test_set_reference(self):
  2275. bar = self.store.get(Bar, 100)
  2276. self.assertEquals(bar.foo.id, 10)
  2277. foo = self.store.get(Foo, 30)
  2278. bar.foo = foo
  2279. self.assertEquals(bar.foo.id, 30)
  2280. result = self.store.execute("SELECT foo_id FROM bar WHERE id=100")
  2281. self.assertEquals(result.get_one(), (30,))
  2282. def test_set_reference_explicitly_with_wrapper(self):
  2283. bar = self.store.get(Bar, 100)
  2284. self.assertEquals(bar.foo.id, 10)
  2285. foo = self.store.get(Foo, 30)
  2286. Bar.foo.__set__(Wrapper(bar), Wrapper(foo))
  2287. self.assertEquals(bar.foo.id, 30)
  2288. result = self.store.execute("SELECT foo_id FROM bar WHERE id=100")
  2289. self.assertEquals(result.get_one(), (30,))
  2290. def test_reference_assign_remote_key(self):
  2291. bar = self.store.get(Bar, 100)
  2292. self.assertEquals(bar.foo.id, 10)
  2293. bar.foo = 30
  2294. self.assertEquals(bar.foo_id, 30)
  2295. self.assertEquals(bar.foo.id, 30)
  2296. result = self.store.execute("SELECT foo_id FROM bar WHERE id=100")
  2297. self.assertEquals(result.get_one(), (30,))
  2298. def test_reference_on_added(self):
  2299. foo = Foo()
  2300. foo.title = u"Title 40"
  2301. self.store.add(foo)
  2302. bar = Bar()
  2303. bar.id = 400
  2304. bar.title = u"Title 400"
  2305. bar.foo = foo
  2306. self.store.add(bar)
  2307. self.assertEquals(bar.foo.id, None)
  2308. self.assertEquals(bar.foo.title, "Title 40")
  2309. self.store.flush()
  2310. self.assertTrue(bar.foo.id)
  2311. self.assertEquals(bar.foo.title, "Title 40")
  2312. result = self.store.execute("SELECT foo.title FROM foo, bar "
  2313. "WHERE bar.id=400 AND "
  2314. "foo.id = bar.foo_id")
  2315. self.assertEquals(result.get_one(), ("Title 40",))
  2316. def test_reference_on_added_with_autoreload_key(self):
  2317. foo = Foo()
  2318. foo.title = u"Title 40"
  2319. self.store.add(foo)
  2320. bar = Bar()
  2321. bar.id = 400
  2322. bar.title = u"Title 400"
  2323. bar.foo = foo
  2324. self.store.add(bar)
  2325. self.assertEquals(bar.foo.id, None)
  2326. self.assertEquals(bar.foo.title, "Title 40")
  2327. foo.id = AutoReload
  2328. # Variable shouldn't be autoreloaded yet.
  2329. obj_info = get_obj_info(foo)
  2330. self.assertEquals(obj_info.variables[Foo.id].get_lazy(), AutoReload)
  2331. self.assertEquals(type(foo.id), int)
  2332. self.store.flush()
  2333. self.assertTrue(bar.foo.id)
  2334. self.assertEquals(bar.foo.title, "Title 40")
  2335. result = self.store.execute("SELECT foo.title FROM foo, bar "
  2336. "WHERE bar.id=400 AND "
  2337. "foo.id = bar.foo_id")
  2338. self.assertEquals(result.get_one(), ("Title 40",))
  2339. def test_reference_assign_none(self):
  2340. foo = Foo()
  2341. foo.title = u"Title 40"
  2342. bar = Bar()
  2343. bar.id = 400
  2344. bar.title = u"Title 400"
  2345. bar.foo = foo
  2346. bar.foo = None
  2347. bar.foo = None # Twice to make sure it doesn't blow up.
  2348. self.store.add(bar)
  2349. self.store.flush()
  2350. self.assertEquals(type(bar.id), int)
  2351. self.assertEquals(foo.id, None)
  2352. def test_reference_assign_none_with_unseen(self):
  2353. bar = self.store.get(Bar, 200)
  2354. bar.foo = None
  2355. self.assertEquals(bar.foo, None)
  2356. def test_reference_on_added_composed_key(self):
  2357. class Bar(object):
  2358. __storm_table__ = "bar"
  2359. id = Int(primary=True)
  2360. foo_id = Int()
  2361. title = Unicode()
  2362. foo = Reference((foo_id, title), (Foo.id, Foo.title))
  2363. foo = Foo()
  2364. foo.title = u"Title 40"
  2365. self.store.add(foo)
  2366. bar = Bar()
  2367. bar.id = 400
  2368. bar.foo = foo
  2369. self.store.add(bar)
  2370. self.assertEquals(bar.foo.id, None)
  2371. self.assertEquals(bar.foo.title, "Title 40")
  2372. self.assertEquals(bar.title, "Title 40")
  2373. self.store.flush()
  2374. self.assertTrue(bar.foo.id)
  2375. self.assertEquals(bar.foo.title, "Title 40")
  2376. result = self.store.execute("SELECT foo.title FROM foo, bar "
  2377. "WHERE bar.id=400 AND "
  2378. "foo.id = bar.foo_id")
  2379. self.assertEquals(result.get_one(), ("Title 40",))
  2380. def test_reference_assign_composed_remote_key(self):
  2381. class Bar(object):
  2382. __storm_table__ = "bar"
  2383. id = Int(primary=True)
  2384. foo_id = Int()
  2385. title = Unicode()
  2386. foo = Reference((foo_id, title), (Foo.id, Foo.title))
  2387. bar = Bar()
  2388. bar.id = 400
  2389. bar.foo = (20, u"Title 20")
  2390. self.store.add(bar)
  2391. self.assertEquals(bar.foo_id, 20)
  2392. self.assertEquals(bar.foo.id, 20)
  2393. self.assertEquals(bar.title, "Title 20")
  2394. self.assertEquals(bar.foo.title, "Title 20")
  2395. def test_reference_on_added_unlink_on_flush(self):
  2396. foo = Foo()
  2397. foo.title = u"Title 40"
  2398. self.store.add(foo)
  2399. bar = Bar()
  2400. bar.id = 400
  2401. bar.foo = foo
  2402. bar.title = u"Title 400"
  2403. self.store.add(bar)
  2404. foo.id = 40
  2405. self.assertEquals(bar.foo_id, 40)
  2406. foo.id = 50
  2407. self.assertEquals(bar.foo_id, 50)
  2408. foo.id = 60
  2409. self.assertEquals(bar.foo_id, 60)
  2410. self.store.flush()
  2411. foo.id = 70
  2412. self.assertEquals(bar.foo_id, 60)
  2413. def test_reference_on_added_unsets_original_key(self):
  2414. foo = Foo()
  2415. self.store.add(foo)
  2416. bar = Bar()
  2417. bar.id = 400
  2418. bar.foo_id = 40
  2419. bar.foo = foo
  2420. self.assertEquals(bar.foo_id, None)
  2421. def test_reference_on_two_added(self):
  2422. foo1 = Foo()
  2423. foo1.title = u"Title 40"
  2424. foo2 = Foo()
  2425. foo2.title = u"Title 40"
  2426. self.store.add(foo1)
  2427. self.store.add(foo2)
  2428. bar = Bar()
  2429. bar.id = 400
  2430. bar.title = u"Title 400"
  2431. bar.foo = foo1
  2432. bar.foo = foo2
  2433. self.store.add(bar)
  2434. foo1.id = 40
  2435. self.assertEquals(bar.foo_id, None)
  2436. foo2.id = 50
  2437. self.assertEquals(bar.foo_id, 50)
  2438. def test_reference_on_added_and_changed_manually(self):
  2439. foo = Foo()
  2440. foo.title = u"Title 40"
  2441. self.store.add(foo)
  2442. bar = Bar()
  2443. bar.id = 400
  2444. bar.title = u"Title 400"
  2445. bar.foo = foo
  2446. self.store.add(bar)
  2447. bar.foo_id = 40
  2448. foo.id = 50
  2449. self.assertEquals(bar.foo_id, 40)
  2450. def test_reference_on_added_composed_key_changed_manually(self):
  2451. class Bar(object):
  2452. __storm_table__ = "bar"
  2453. id = Int(primary=True)
  2454. foo_id = Int()
  2455. title = Unicode()
  2456. foo = Reference((foo_id, title), (Foo.id, Foo.title))
  2457. foo = Foo()
  2458. foo.title = u"Title 40"
  2459. self.store.add(foo)
  2460. bar = Bar()
  2461. bar.id = 400
  2462. bar.foo = foo
  2463. self.store.add(bar)
  2464. bar.title = u"Title 50"
  2465. self.assertEquals(bar.foo, None)
  2466. foo.id = 40
  2467. self.assertEquals(bar.foo_id, None)
  2468. def test_reference_on_added_no_local_store(self):
  2469. foo = Foo()
  2470. foo.title = u"Title 40"
  2471. self.store.add(foo)
  2472. bar = Bar()
  2473. bar.id = 400
  2474. bar.title = u"Title 400"
  2475. bar.foo = foo
  2476. self.assertEquals(Store.of(bar), self.store)
  2477. self.assertEquals(Store.of(foo), self.store)
  2478. def test_reference_on_added_no_remote_store(self):
  2479. foo = Foo()
  2480. foo.title = u"Title 40"
  2481. bar = Bar()
  2482. bar.id = 400
  2483. bar.title = u"Title 400"
  2484. self.store.add(bar)
  2485. bar.foo = foo
  2486. self.assertEquals(Store.of(bar), self.store)
  2487. self.assertEquals(Store.of(foo), self.store)
  2488. def test_reference_on_added_no_store(self):
  2489. foo = Foo()
  2490. foo.title = u"Title 40"
  2491. bar = Bar()
  2492. bar.id = 400
  2493. bar.title = u"Title 400"
  2494. bar.foo = foo
  2495. self.store.add(bar)
  2496. self.assertEquals(Store.of(bar), self.store)
  2497. self.assertEquals(Store.of(foo), self.store)
  2498. self.store.flush()
  2499. self.assertEquals(type(bar.foo_id), int)
  2500. def test_reference_on_added_no_store_2(self):
  2501. foo = Foo()
  2502. foo.title = u"Title 40"
  2503. bar = Bar()
  2504. bar.id = 400
  2505. bar.title = u"Title 400"
  2506. bar.foo = foo
  2507. self.store.add(foo)
  2508. self.assertEquals(Store.of(bar), self.store)
  2509. self.assertEquals(Store.of(foo), self.store)
  2510. self.store.flush()
  2511. self.assertEquals(type(bar.foo_id), int)
  2512. def test_reference_on_added_wrong_store(self):
  2513. store = self.create_store()
  2514. foo = Foo()
  2515. foo.title = u"Title 40"
  2516. store.add(foo)
  2517. bar = Bar()
  2518. bar.id = 400
  2519. bar.title = u"Title 400"
  2520. self.store.add(bar)
  2521. self.assertRaises(WrongStoreError, setattr, bar, "foo", foo)
  2522. def test_reference_on_added_no_store_unlink_before_adding(self):
  2523. foo1 = Foo()
  2524. foo1.title = u"Title 40"
  2525. bar = Bar()
  2526. bar.id = 400
  2527. bar.title = u"Title 400"
  2528. bar.foo = foo1
  2529. bar.foo = None
  2530. self.store.add(bar)
  2531. store = self.create_store()
  2532. store.add(foo1)
  2533. self.assertEquals(Store.of(bar), self.store)
  2534. self.assertEquals(Store.of(foo1), store)
  2535. def test_reference_on_removed_wont_add_back(self):
  2536. bar = self.store.get(Bar, 200)
  2537. foo = self.store.get(Foo, bar.foo_id)
  2538. self.store.remove(bar)
  2539. self.assertEquals(bar.foo, foo)
  2540. self.store.flush()
  2541. self.assertEquals(Store.of(bar), None)
  2542. self.assertEquals(Store.of(foo), self.store)
  2543. def test_reference_equals(self):
  2544. foo = self.store.get(Foo, 10)
  2545. bar = self.store.find(Bar, foo=foo).one()
  2546. self.assertTrue(bar)
  2547. self.assertEquals(bar.foo, foo)
  2548. bar = self.store.find(Bar, foo=foo.id).one()
  2549. self.assertTrue(bar)
  2550. self.assertEquals(bar.foo, foo)
  2551. def test_reference_equals_none(self):
  2552. result = list(self.store.find(SelfRef, selfref=None))
  2553. self.assertEquals(len(result), 2)
  2554. self.assertEquals(result[0].selfref, None)
  2555. self.assertEquals(result[1].selfref, None)
  2556. def test_reference_equals_with_composed_key(self):
  2557. # Interesting case of self-reference.
  2558. class LinkWithRef(Link):
  2559. myself = Reference((Link.foo_id, Link.bar_id),
  2560. (Link.foo_id, Link.bar_id))
  2561. link = self.store.find(LinkWithRef, foo_id=10, bar_id=100).one()
  2562. myself = self.store.find(LinkWithRef, myself=link).one()
  2563. self.assertEquals(link, myself)
  2564. myself = self.store.find(LinkWithRef,
  2565. myself=(link.foo_id, link.bar_id)).one()
  2566. self.assertEquals(link, myself)
  2567. def test_reference_equals_with_wrapped(self):
  2568. foo = self.store.get(Foo, 10)
  2569. bar = self.store.find(Bar, foo=Wrapper(foo)).one()
  2570. self.assertTrue(bar)
  2571. self.assertEquals(bar.foo, foo)
  2572. def test_reference_not_equals(self):
  2573. foo = self.store.get(Foo, 10)
  2574. result = self.store.find(Bar, Bar.foo != foo)
  2575. self.assertEquals([200, 300], sorted(bar.id for bar in result))
  2576. def test_reference_not_equals_none(self):
  2577. obj = self.store.find(SelfRef, SelfRef.selfref != None).one()
  2578. self.assertTrue(obj)
  2579. self.assertNotEquals(obj.selfref, None)
  2580. def test_reference_not_equals_with_composed_key(self):
  2581. class LinkWithRef(Link):
  2582. myself = Reference((Link.foo_id, Link.bar_id),
  2583. (Link.foo_id, Link.bar_id))
  2584. link = self.store.find(LinkWithRef, foo_id=10, bar_id=100).one()
  2585. result = list(self.store.find(LinkWithRef, LinkWithRef.myself != link))
  2586. self.assertTrue(link not in result, "%r not in %r" % (link, result))
  2587. result = list(self.store.find(
  2588. LinkWithRef, LinkWithRef.myself != (link.foo_id, link.bar_id)))
  2589. self.assertTrue(link not in result, "%r not in %r" % (link, result))
  2590. def test_reference_self(self):
  2591. selfref = self.store.add(SelfRef())
  2592. selfref.id = 400
  2593. selfref.title = u"Title 400"
  2594. selfref.selfref_id = 25
  2595. self.assertEquals(selfref.selfref.id, 25)
  2596. self.assertEquals(selfref.selfref.title, "SelfRef 25")
  2597. def get_bar_200_title(self):
  2598. connection = self.store._connection
  2599. result = connection.execute("SELECT title FROM bar WHERE id=200")
  2600. return result.get_one()[0]
  2601. def test_reference_wont_touch_store_when_key_is_none(self):
  2602. bar = self.store.get(Bar, 200)
  2603. bar.foo_id = None
  2604. bar.title = u"Don't flush this!"
  2605. self.assertEquals(bar.foo, None)
  2606. # Bypass the store to prevent flushing.
  2607. self.assertEquals(self.get_bar_200_title(), "Title 200")
  2608. def test_reference_wont_touch_store_when_key_is_unset(self):
  2609. bar = self.store.get(Bar, 200)
  2610. del bar.foo_id
  2611. bar.title = u"Don't flush this!"
  2612. self.assertEquals(bar.foo, None)
  2613. # Bypass the store to prevent flushing.
  2614. connection = self.store._connection
  2615. result = connection.execute("SELECT title FROM bar WHERE id=200")
  2616. self.assertEquals(result.get_one()[0], "Title 200")
  2617. def test_reference_wont_touch_store_with_composed_key_none(self):
  2618. class Bar(object):
  2619. __storm_table__ = "bar"
  2620. id = Int(primary=True)
  2621. foo_id = Int()
  2622. title = Unicode()
  2623. foo = Reference((foo_id, title), (Foo.id, Foo.title))
  2624. bar = self.store.get(Bar, 200)
  2625. bar.foo_id = None
  2626. bar.title = None
  2627. self.assertEquals(bar.foo, None)
  2628. # Bypass the store to prevent flushing.
  2629. self.assertEquals(self.get_bar_200_title(), "Title 200")
  2630. def test_reference_will_resolve_auto_reload(self):
  2631. bar = self.store.get(Bar, 200)
  2632. bar.foo_id = AutoReload
  2633. self.assertTrue(bar.foo)
  2634. def test_back_reference(self):
  2635. class MyFoo(Foo):
  2636. bar = Reference(Foo.id, Bar.foo_id, on_remote=True)
  2637. foo = self.store.get(MyFoo, 10)
  2638. self.assertTrue(foo.bar)
  2639. self.assertEquals(foo.bar.title, "Title 300")
  2640. def test_back_reference_setting(self):
  2641. class MyFoo(Foo):
  2642. bar = Reference(Foo.id, Bar.foo_id, on_remote=True)
  2643. bar = Bar()
  2644. bar.title = u"Title 400"
  2645. self.store.add(bar)
  2646. foo = MyFoo()
  2647. foo.bar = bar
  2648. foo.title = u"Title 40"
  2649. self.store.add(foo)
  2650. self.store.flush()
  2651. self.assertTrue(foo.id)
  2652. self.assertEquals(bar.foo_id, foo.id)
  2653. result = self.store.execute("SELECT bar.title "
  2654. "FROM foo, bar "
  2655. "WHERE foo.id = bar.foo_id AND "
  2656. "foo.title = 'Title 40'")
  2657. self.assertEquals(result.get_one(), ("Title 400",))
  2658. def test_back_reference_setting_changed_manually(self):
  2659. class MyFoo(Foo):
  2660. bar = Reference(Foo.id, Bar.foo_id, on_remote=True)
  2661. bar = Bar()
  2662. bar.title = u"Title 400"
  2663. self.store.add(bar)
  2664. foo = MyFoo()
  2665. foo.bar = bar
  2666. foo.title = u"Title 40"
  2667. self.store.add(foo)
  2668. foo.id = 40
  2669. self.assertEquals(foo.bar, bar)
  2670. self.store.flush()
  2671. self.assertEquals(foo.id, 40)
  2672. self.assertEquals(bar.foo_id, 40)
  2673. result = self.store.execute("SELECT bar.title "
  2674. "FROM foo, bar "
  2675. "WHERE foo.id = bar.foo_id AND "
  2676. "foo.title = 'Title 40'")
  2677. self.assertEquals(result.get_one(), ("Title 400",))
  2678. def test_back_reference_assign_none_with_unseen(self):
  2679. class MyFoo(Foo):
  2680. bar = Reference(Foo.id, Bar.foo_id, on_remote=True)
  2681. foo = self.store.get(MyFoo, 20)
  2682. foo.bar = None
  2683. self.assertEquals(foo.bar, None)
  2684. def test_back_reference_assign_none_from_none(self):
  2685. class MyFoo(Foo):
  2686. bar = Reference(Foo.id, Bar.foo_id, on_remote=True)
  2687. self.store.execute("INSERT INTO foo (id, title)"
  2688. " VALUES (40, 'Title 40')")
  2689. self.store.commit()
  2690. foo = self.store.get(MyFoo, 40)
  2691. foo.bar = None
  2692. self.assertEquals(foo.bar, None)
  2693. def test_back_reference_on_added_unsets_original_key(self):
  2694. class MyFoo(Foo):
  2695. bar = Reference(Foo.id, Bar.foo_id, on_remote=True)
  2696. foo = MyFoo()
  2697. bar = Bar()
  2698. bar.id = 400
  2699. bar.foo_id = 40
  2700. foo.bar = bar
  2701. self.assertEquals(bar.foo_id, None)
  2702. def test_back_reference_on_added_no_store(self):
  2703. class MyFoo(Foo):
  2704. bar = Reference(Foo.id, Bar.foo_id, on_remote=True)
  2705. bar = Bar()
  2706. bar.title = u"Title 400"
  2707. foo = MyFoo()
  2708. foo.bar = bar
  2709. foo.title = u"Title 40"
  2710. self.store.add(bar)
  2711. self.assertEquals(Store.of(bar), self.store)
  2712. self.assertEquals(Store.of(foo), self.store)
  2713. self.store.flush()
  2714. self.assertEquals(type(bar.foo_id), int)
  2715. def test_back_reference_on_added_no_store_2(self):
  2716. class MyFoo(Foo):
  2717. bar = Reference(Foo.id, Bar.foo_id, on_remote=True)
  2718. bar = Bar()
  2719. bar.title = u"Title 400"
  2720. foo = MyFoo()
  2721. foo.bar = bar
  2722. foo.title = u"Title 40"
  2723. self.store.add(foo)
  2724. self.assertEquals(Store.of(bar), self.store)
  2725. self.assertEquals(Store.of(foo), self.store)
  2726. self.store.flush()
  2727. self.assertEquals(type(bar.foo_id), int)
  2728. def test_back_reference_remove_remote(self):
  2729. class MyFoo(Foo):
  2730. bar = Reference(Foo.id, Bar.foo_id, on_remote=True)
  2731. bar = Bar()
  2732. bar.title = u"Title 400"
  2733. foo = MyFoo()
  2734. foo.title = u"Title 40"
  2735. foo.bar = bar
  2736. self.store.add(foo)
  2737. self.store.flush()
  2738. self.assertEquals(foo.bar, bar)
  2739. self.store.remove(bar)
  2740. self.assertEquals(foo.bar, None)
  2741. def test_back_reference_remove_remote_pending_add(self):
  2742. class MyFoo(Foo):
  2743. bar = Reference(Foo.id, Bar.foo_id, on_remote=True)
  2744. bar = Bar()
  2745. bar.title = u"Title 400"
  2746. foo = MyFoo()
  2747. foo.title = u"Title 40"
  2748. foo.bar = bar
  2749. self.store.add(foo)
  2750. self.assertEquals(foo.bar, bar)
  2751. self.store.remove(bar)
  2752. self.assertEquals(foo.bar, None)
  2753. def test_reference_loop_with_undefined_keys_fails(self):
  2754. """A loop of references with undefined keys raises OrderLoopError."""
  2755. ref1 = SelfRef()
  2756. self.store.add(ref1)
  2757. ref2 = SelfRef()
  2758. ref2.selfref = ref1
  2759. ref1.selfref = ref2
  2760. self.assertRaises(OrderLoopError, self.store.flush)
  2761. def test_reference_loop_with_dirty_keys_fails(self):
  2762. ref1 = SelfRef()
  2763. self.store.add(ref1)
  2764. ref1.id = 42
  2765. ref2 = SelfRef()
  2766. ref2.id = 43
  2767. ref2.selfref = ref1
  2768. ref1.selfref = ref2
  2769. self.assertRaises(OrderLoopError, self.store.flush)
  2770. def test_reference_loop_with_dirty_keys_changed_later_fails(self):
  2771. ref1 = SelfRef()
  2772. ref2 = SelfRef()
  2773. self.store.add(ref1)
  2774. self.store.add(ref2)
  2775. self.store.flush()
  2776. ref2.selfref = ref1
  2777. ref1.selfref = ref2
  2778. ref1.id = 42
  2779. ref2.id = 43
  2780. self.assertRaises(OrderLoopError, self.store.flush)
  2781. def test_reference_loop_with_dirty_keys_on_remote_fails(self):
  2782. ref1 = SelfRef()
  2783. self.store.add(ref1)
  2784. ref1.id = 42
  2785. ref2 = SelfRef()
  2786. ref2.id = 43
  2787. ref2.selfref_on_remote = ref1
  2788. ref1.selfref_on_remote = ref2
  2789. self.assertRaises(OrderLoopError, self.store.flush)
  2790. def test_reference_loop_with_dirty_keys_on_remote_changed_later_fails(self):
  2791. ref1 = SelfRef()
  2792. ref2 = SelfRef()
  2793. self.store.add(ref1)
  2794. self.store.flush()
  2795. ref2.selfref_on_remote = ref1
  2796. ref1.selfref_on_remote = ref2
  2797. ref1.id = 42
  2798. ref2.id = 43
  2799. self.assertRaises(OrderLoopError, self.store.flush)
  2800. def test_reference_loop_with_unchanged_keys_succeeds(self):
  2801. ref1 = SelfRef()
  2802. self.store.add(ref1)
  2803. ref1.id = 42
  2804. ref2 = SelfRef()
  2805. self.store.add(ref2)
  2806. ref1.id = 43
  2807. self.store.flush()
  2808. # As ref1 and ref2 have been flushed to the database, so these
  2809. # changes can be flushed.
  2810. ref2.selfref = ref1
  2811. ref1.selfref = ref2
  2812. self.store.flush()
  2813. def test_reference_loop_with_one_unchanged_key_succeeds(self):
  2814. ref1 = SelfRef()
  2815. self.store.add(ref1)
  2816. self.store.flush()
  2817. ref2 = SelfRef()
  2818. ref2.selfref = ref1
  2819. ref1.selfref = ref2
  2820. # As ref1 and ref2 have been flushed to the database, so these
  2821. # changes can be flushed.
  2822. self.store.flush()
  2823. def test_reference_loop_with_key_changed_later_succeeds(self):
  2824. ref1 = SelfRef()
  2825. self.store.add(ref1)
  2826. self.store.flush()
  2827. ref2 = SelfRef()
  2828. ref1.selfref = ref2
  2829. ref2.id = 42
  2830. self.store.flush()
  2831. def test_reference_loop_with_key_changed_later_on_remote_succeeds(self):
  2832. ref1 = SelfRef()
  2833. self.store.add(ref1)
  2834. self.store.flush()
  2835. ref2 = SelfRef()
  2836. ref2.selfref_on_remote = ref1
  2837. ref2.id = 42
  2838. self.store.flush()
  2839. def test_reference_loop_with_undefined_and_changed_keys_fails(self):
  2840. ref1 = SelfRef()
  2841. self.store.add(ref1)
  2842. self.store.flush()
  2843. ref1.id = 400
  2844. ref2 = SelfRef()
  2845. ref2.selfref = ref1
  2846. ref1.selfref = ref2
  2847. self.assertRaises(OrderLoopError, self.store.flush)
  2848. def test_reference_loop_with_undefined_and_changed_keys_fails2(self):
  2849. ref1 = SelfRef()
  2850. self.store.add(ref1)
  2851. self.store.flush()
  2852. ref2 = SelfRef()
  2853. ref2.selfref = ref1
  2854. ref1.selfref = ref2
  2855. ref1.id = 400
  2856. self.assertRaises(OrderLoopError, self.store.flush)
  2857. def test_reference_loop_broken_by_set(self):
  2858. ref1 = SelfRef()
  2859. ref2 = SelfRef()
  2860. ref1.selfref = ref2
  2861. ref2.selfref = ref1
  2862. self.store.add(ref1)
  2863. ref1.selfref = None
  2864. self.store.flush()
  2865. def test_reference_loop_set_only_removes_own_flush_order(self):
  2866. ref1 = SelfRef()
  2867. ref2 = SelfRef()
  2868. self.store.add(ref2)
  2869. self.store.flush()
  2870. # The following does not create a loop since the keys are
  2871. # dirty (as shown in another test).
  2872. ref1.selfref = ref2
  2873. ref2.selfref = ref1
  2874. # Now add a flush order loop.
  2875. self.store.add_flush_order(ref1, ref2)
  2876. self.store.add_flush_order(ref2, ref1)
  2877. # Now break the reference. This should leave the flush
  2878. # ordering loop we previously created in place..
  2879. ref1.selfref = None
  2880. self.assertRaises(OrderLoopError, self.store.flush)
  2881. def add_reference_set_bar_400(self):
  2882. bar = Bar()
  2883. bar.id = 400
  2884. bar.foo_id = 20
  2885. bar.title = u"Title 100"
  2886. self.store.add(bar)
  2887. def test_reference_set(self):
  2888. self.add_reference_set_bar_400()
  2889. foo = self.store.get(FooRefSet, 20)
  2890. items = []
  2891. for bar in foo.bars:
  2892. items.append((bar.id, bar.foo_id, bar.title))
  2893. items.sort()
  2894. self.assertEquals(items, [
  2895. (200, 20, "Title 200"),
  2896. (400, 20, "Title 100"),
  2897. ])
  2898. def test_reference_set_assign_fails(self):
  2899. foo = self.store.get(FooRefSet, 20)
  2900. try:
  2901. foo.bars = []
  2902. except FeatureError:
  2903. pass
  2904. else:
  2905. self.fail("FeatureError not raised")
  2906. def test_reference_set_explicitly_with_wrapper(self):
  2907. self.add_reference_set_bar_400()
  2908. foo = self.store.get(FooRefSet, 20)
  2909. items = []
  2910. for bar in FooRefSet.bars.__get__(Wrapper(foo)):
  2911. items.append((bar.id, bar.foo_id, bar.title))
  2912. items.sort()
  2913. self.assertEquals(items, [
  2914. (200, 20, "Title 200"),
  2915. (400, 20, "Title 100"),
  2916. ])
  2917. def test_reference_set_with_added(self):
  2918. bar1 = Bar()
  2919. bar1.id = 400
  2920. bar1.title = u"Title 400"
  2921. bar2 = Bar()
  2922. bar2.id = 500
  2923. bar2.title = u"Title 500"
  2924. foo = FooRefSet()
  2925. foo.title = u"Title 40"
  2926. foo.bars.add(bar1)
  2927. foo.bars.add(bar2)
  2928. self.store.add(foo)
  2929. self.assertEquals(foo.id, None)
  2930. self.assertEquals(bar1.foo_id, None)
  2931. self.assertEquals(bar2.foo_id, None)
  2932. self.assertEquals(list(foo.bars.order_by(Bar.id)),
  2933. [bar1, bar2])
  2934. self.assertEquals(type(foo.id), int)
  2935. self.assertEquals(foo.id, bar1.foo_id)
  2936. self.assertEquals(foo.id, bar2.foo_id)
  2937. def test_reference_set_composed(self):
  2938. self.add_reference_set_bar_400()
  2939. bar = self.store.get(Bar, 400)
  2940. bar.title = u"Title 20"
  2941. class FooRefSetComposed(Foo):
  2942. bars = ReferenceSet((Foo.id, Foo.title),
  2943. (Bar.foo_id, Bar.title))
  2944. foo = self.store.get(FooRefSetComposed, 20)
  2945. items = []
  2946. for bar in foo.bars:
  2947. items.append((bar.id, bar.foo_id, bar.title))
  2948. self.assertEquals(items, [
  2949. (400, 20, "Title 20"),
  2950. ])
  2951. bar = self.store.get(Bar, 200)
  2952. bar.title = u"Title 20"
  2953. del items[:]
  2954. for bar in foo.bars:
  2955. items.append((bar.id, bar.foo_id, bar.title))
  2956. items.sort()
  2957. self.assertEquals(items, [
  2958. (200, 20, "Title 20"),
  2959. (400, 20, "Title 20"),
  2960. ])
  2961. def test_reference_set_contains(self):
  2962. def no_iter(self):
  2963. raise RuntimeError()
  2964. from storm.references import BoundReferenceSetBase
  2965. orig_iter = BoundReferenceSetBase.__iter__
  2966. BoundReferenceSetBase.__iter__ = no_iter
  2967. try:
  2968. foo = self.store.get(FooRefSet, 20)
  2969. bar = self.store.get(Bar, 200)
  2970. self.assertEquals(bar in foo.bars, True)
  2971. finally:
  2972. BoundReferenceSetBase.__iter__ = orig_iter
  2973. def test_reference_set_find(self):
  2974. self.add_reference_set_bar_400()
  2975. foo = self.store.get(FooRefSet, 20)
  2976. items = []
  2977. for bar in foo.bars.find():
  2978. items.append((bar.id, bar.foo_id, bar.title))
  2979. items.sort()
  2980. self.assertEquals(items, [
  2981. (200, 20, "Title 200"),
  2982. (400, 20, "Title 100"),
  2983. ])
  2984. # Notice that there's another item with this title in the base,
  2985. # which isn't part of the reference.
  2986. objects = list(foo.bars.find(Bar.title == u"Title 100"))
  2987. self.assertEquals(len(objects), 1)
  2988. self.assertTrue(objects[0] is bar)
  2989. objects = list(foo.bars.find(title=u"Title 100"))
  2990. self.assertEquals(len(objects), 1)
  2991. self.assertTrue(objects[0] is bar)
  2992. def test_reference_set_clear(self):
  2993. foo = self.store.get(FooRefSet, 20)
  2994. foo.bars.clear()
  2995. self.assertEquals(list(foo.bars), [])
  2996. # Object wasn't removed.
  2997. self.assertTrue(self.store.get(Bar, 200))
  2998. def test_reference_set_clear_cached(self):
  2999. foo = self.store.get(FooRefSet, 20)
  3000. bar = self.store.get(Bar, 200)
  3001. self.assertEquals(bar.foo_id, 20)
  3002. foo.bars.clear()
  3003. self.assertEquals(bar.foo_id, None)
  3004. def test_reference_set_clear_where(self):
  3005. self.add_reference_set_bar_400()
  3006. foo = self.store.get(FooRefSet, 20)
  3007. foo.bars.clear(Bar.id > 200)
  3008. items = [(bar.id, bar.foo_id, bar.title) for bar in foo.bars]
  3009. self.assertEquals(items, [
  3010. (200, 20, "Title 200"),
  3011. ])
  3012. bar = self.store.get(Bar, 400)
  3013. bar.foo_id = 20
  3014. foo.bars.clear(id=200)
  3015. items = [(bar.id, bar.foo_id, bar.title) for bar in foo.bars]
  3016. self.assertEquals(items, [
  3017. (400, 20, "Title 100"),
  3018. ])
  3019. def test_reference_set_count(self):
  3020. self.add_reference_set_bar_400()
  3021. foo = self.store.get(FooRefSet, 20)
  3022. self.assertEquals(foo.bars.count(), 2)
  3023. def test_reference_set_order_by(self):
  3024. self.add_reference_set_bar_400()
  3025. foo = self.store.get(FooRefSet, 20)
  3026. items = []
  3027. for bar in foo.bars.order_by(Bar.id):
  3028. items.append((bar.id, bar.foo_id, bar.title))
  3029. self.assertEquals(items, [
  3030. (200, 20, "Title 200"),
  3031. (400, 20, "Title 100"),
  3032. ])
  3033. del items[:]
  3034. for bar in foo.bars.order_by(Bar.title):
  3035. items.append((bar.id, bar.foo_id, bar.title))
  3036. self.assertEquals(items, [
  3037. (400, 20, "Title 100"),
  3038. (200, 20, "Title 200"),
  3039. ])
  3040. def test_reference_set_default_order_by(self):
  3041. self.add_reference_set_bar_400()
  3042. foo = self.store.get(FooRefSetOrderID, 20)
  3043. items = []
  3044. for bar in foo.bars:
  3045. items.append((bar.id, bar.foo_id, bar.title))
  3046. self.assertEquals(items, [
  3047. (200, 20, "Title 200"),
  3048. (400, 20, "Title 100"),
  3049. ])
  3050. items = []
  3051. for bar in foo.bars.find():
  3052. items.append((bar.id, bar.foo_id, bar.title))
  3053. self.assertEquals(items, [
  3054. (200, 20, "Title 200"),
  3055. (400, 20, "Title 100"),
  3056. ])
  3057. foo = self.store.get(FooRefSetOrderTitle, 20)
  3058. del items[:]
  3059. for bar in foo.bars:
  3060. items.append((bar.id, bar.foo_id, bar.title))
  3061. self.assertEquals(items, [
  3062. (400, 20, "Title 100"),
  3063. (200, 20, "Title 200"),
  3064. ])
  3065. del items[:]
  3066. for bar in foo.bars.find():
  3067. items.append((bar.id, bar.foo_id, bar.title))
  3068. self.assertEquals(items, [
  3069. (400, 20, "Title 100"),
  3070. (200, 20, "Title 200"),
  3071. ])
  3072. def test_reference_set_first_last(self):
  3073. self.add_reference_set_bar_400()
  3074. foo = self.store.get(FooRefSetOrderID, 20)
  3075. self.assertEquals(foo.bars.first().id, 200)
  3076. self.assertEquals(foo.bars.last().id, 400)
  3077. foo = self.store.get(FooRefSetOrderTitle, 20)
  3078. self.assertEquals(foo.bars.first().id, 400)
  3079. self.assertEquals(foo.bars.last().id, 200)
  3080. foo = self.store.get(FooRefSetOrderTitle, 20)
  3081. self.assertEquals(foo.bars.first(Bar.id > 400), None)
  3082. self.assertEquals(foo.bars.last(Bar.id > 400), None)
  3083. foo = self.store.get(FooRefSetOrderTitle, 20)
  3084. self.assertEquals(foo.bars.first(Bar.id < 400).id, 200)
  3085. self.assertEquals(foo.bars.last(Bar.id < 400).id, 200)
  3086. foo = self.store.get(FooRefSetOrderTitle, 20)
  3087. self.assertEquals(foo.bars.first(id=200).id, 200)
  3088. self.assertEquals(foo.bars.last(id=200).id, 200)
  3089. foo = self.store.get(FooRefSet, 20)
  3090. self.assertRaises(UnorderedError, foo.bars.first)
  3091. self.assertRaises(UnorderedError, foo.bars.last)
  3092. def test_indirect_reference_set_any(self):
  3093. """
  3094. L{BoundReferenceSet.any} returns an arbitrary object from the set of
  3095. referenced objects.
  3096. """
  3097. foo = self.store.get(FooRefSet, 20)
  3098. self.assertNotEqual(None, foo.bars.any())
  3099. def test_indirect_reference_set_any_filtered(self):
  3100. """
  3101. L{BoundReferenceSet.any} optionally takes a list of filtering criteria
  3102. to narrow the set of objects to search. When provided, the criteria
  3103. are used to filter the set before returning an arbitrary object.
  3104. """
  3105. self.add_reference_set_bar_400()
  3106. foo = self.store.get(FooRefSetOrderTitle, 20)
  3107. self.assertEquals(foo.bars.any(Bar.id > 400), None)
  3108. foo = self.store.get(FooRefSetOrderTitle, 20)
  3109. self.assertEquals(foo.bars.any(Bar.id < 400).id, 200)
  3110. foo = self.store.get(FooRefSetOrderTitle, 20)
  3111. self.assertEquals(foo.bars.any(id=200).id, 200)
  3112. def test_reference_set_one(self):
  3113. self.add_reference_set_bar_400()
  3114. foo = self.store.get(FooRefSetOrderID, 20)
  3115. self.assertRaises(NotOneError, foo.bars.one)
  3116. foo = self.store.get(FooRefSetOrderID, 30)
  3117. self.assertEquals(foo.bars.one().id, 300)
  3118. foo = self.store.get(FooRefSetOrderID, 20)
  3119. self.assertEquals(foo.bars.one(Bar.id > 400), None)
  3120. foo = self.store.get(FooRefSetOrderID, 20)
  3121. self.assertEquals(foo.bars.one(Bar.id < 400).id, 200)
  3122. foo = self.store.get(FooRefSetOrderID, 20)
  3123. self.assertEquals(foo.bars.one(id=200).id, 200)
  3124. def test_reference_set_remove(self):
  3125. self.add_reference_set_bar_400()
  3126. foo = self.store.get(FooRefSet, 20)
  3127. for bar in foo.bars:
  3128. foo.bars.remove(bar)
  3129. self.assertEquals(bar.foo_id, None)
  3130. self.assertEquals(list(foo.bars), [])
  3131. def test_reference_set_after_object_removed(self):
  3132. class MyBar(Bar):
  3133. # Make sure that this works even with allow_none=False.
  3134. foo_id = Int(allow_none=False)
  3135. class MyFoo(Foo):
  3136. bars = ReferenceSet(Foo.id, MyBar.foo_id)
  3137. foo = self.store.get(MyFoo, 20)
  3138. bar = foo.bars.any()
  3139. self.store.remove(bar)
  3140. self.assertTrue(bar not in list(foo.bars))
  3141. def test_reference_set_add(self):
  3142. bar = Bar()
  3143. bar.id = 400
  3144. bar.title = u"Title 100"
  3145. foo = self.store.get(FooRefSet, 20)
  3146. foo.bars.add(bar)
  3147. self.assertEquals(bar.foo_id, 20)
  3148. self.assertEquals(Store.of(bar), self.store)
  3149. def test_reference_set_add_no_store(self):
  3150. bar = Bar()
  3151. bar.id = 400
  3152. bar.title = u"Title 400"
  3153. foo = FooRefSet()
  3154. foo.title = u"Title 40"
  3155. foo.bars.add(bar)
  3156. self.store.add(foo)
  3157. self.assertEquals(Store.of(foo), self.store)
  3158. self.assertEquals(Store.of(bar), self.store)
  3159. self.store.flush()
  3160. self.assertEquals(type(bar.foo_id), int)
  3161. def test_reference_set_add_no_store_2(self):
  3162. bar = Bar()
  3163. bar.id = 400
  3164. bar.title = u"Title 400"
  3165. foo = FooRefSet()
  3166. foo.title = u"Title 40"
  3167. foo.bars.add(bar)
  3168. self.store.add(bar)
  3169. self.assertEquals(Store.of(foo), self.store)
  3170. self.assertEquals(Store.of(bar), self.store)
  3171. self.store.flush()
  3172. self.assertEquals(type(bar.foo_id), int)
  3173. def test_reference_set_add_no_store_unlink_after_adding(self):
  3174. bar1 = Bar()
  3175. bar1.id = 400
  3176. bar1.title = u"Title 400"
  3177. bar2 = Bar()
  3178. bar2.id = 500
  3179. bar2.title = u"Title 500"
  3180. foo = FooRefSet()
  3181. foo.title = u"Title 40"
  3182. foo.bars.add(bar1)
  3183. foo.bars.add(bar2)
  3184. foo.bars.remove(bar1)
  3185. self.store.add(foo)
  3186. store = self.create_store()
  3187. store.add(bar1)
  3188. self.assertEquals(Store.of(foo), self.store)
  3189. self.assertEquals(Store.of(bar1), store)
  3190. self.assertEquals(Store.of(bar2), self.store)
  3191. def test_reference_set_values(self):
  3192. self.add_reference_set_bar_400()
  3193. foo = self.store.get(FooRefSetOrderID, 20)
  3194. values = list(foo.bars.values(Bar.id, Bar.foo_id, Bar.title))
  3195. self.assertEquals(values, [
  3196. (200, 20, "Title 200"),
  3197. (400, 20, "Title 100"),
  3198. ])
  3199. def test_indirect_reference_set(self):
  3200. foo = self.store.get(FooIndRefSet, 20)
  3201. items = []
  3202. for bar in foo.bars:
  3203. items.append((bar.id, bar.title))
  3204. items.sort()
  3205. self.assertEquals(items, [
  3206. (100, "Title 300"),
  3207. (200, "Title 200"),
  3208. ])
  3209. def test_indirect_reference_set_with_added(self):
  3210. bar1 = Bar()
  3211. bar1.id = 400
  3212. bar1.title = u"Title 400"
  3213. bar2 = Bar()
  3214. bar2.id = 500
  3215. bar2.title = u"Title 500"
  3216. self.store.add(bar1)
  3217. self.store.add(bar2)
  3218. foo = FooIndRefSet()
  3219. foo.title = u"Title 40"
  3220. foo.bars.add(bar1)
  3221. foo.bars.add(bar2)
  3222. self.assertEquals(foo.id, None)
  3223. self.store.add(foo)
  3224. self.assertEquals(foo.id, None)
  3225. self.assertEquals(bar1.foo_id, None)
  3226. self.assertEquals(bar2.foo_id, None)
  3227. self.assertEquals(list(foo.bars.order_by(Bar.id)),
  3228. [bar1, bar2])
  3229. self.assertEquals(type(foo.id), int)
  3230. self.assertEquals(type(bar1.id), int)
  3231. self.assertEquals(type(bar2.id), int)
  3232. def test_indirect_reference_set_find(self):
  3233. foo = self.store.get(FooIndRefSet, 20)
  3234. items = []
  3235. for bar in foo.bars.find(Bar.title == u"Title 300"):
  3236. items.append((bar.id, bar.title))
  3237. items.sort()
  3238. self.assertEquals(items, [
  3239. (100, "Title 300"),
  3240. ])
  3241. def test_indirect_reference_set_clear(self):
  3242. foo = self.store.get(FooIndRefSet, 20)
  3243. foo.bars.clear()
  3244. self.assertEquals(list(foo.bars), [])
  3245. def test_indirect_reference_set_clear_where(self):
  3246. foo = self.store.get(FooIndRefSet, 20)
  3247. items = [(bar.id, bar.foo_id, bar.title) for bar in foo.bars]
  3248. self.assertEquals(items, [
  3249. (100, 10, "Title 300"),
  3250. (200, 20, "Title 200"),
  3251. ])
  3252. foo = self.store.get(FooIndRefSet, 30)
  3253. foo.bars.clear(Bar.id < 300)
  3254. foo.bars.clear(id=200)
  3255. foo = self.store.get(FooIndRefSet, 20)
  3256. foo.bars.clear(Bar.id < 200)
  3257. items = [(bar.id, bar.foo_id, bar.title) for bar in foo.bars]
  3258. self.assertEquals(items, [
  3259. (200, 20, "Title 200"),
  3260. ])
  3261. foo.bars.clear(id=200)
  3262. items = [(bar.id, bar.foo_id, bar.title) for bar in foo.bars]
  3263. self.assertEquals(items, [])
  3264. def test_indirect_reference_set_count(self):
  3265. foo = self.store.get(FooIndRefSet, 20)
  3266. self.assertEquals(foo.bars.count(), 2)
  3267. def test_indirect_reference_set_order_by(self):
  3268. foo = self.store.get(FooIndRefSet, 20)
  3269. items = []
  3270. for bar in foo.bars.order_by(Bar.title):
  3271. items.append((bar.id, bar.title))
  3272. self.assertEquals(items, [
  3273. (200, "Title 200"),
  3274. (100, "Title 300"),
  3275. ])
  3276. del items[:]
  3277. for bar in foo.bars.order_by(Bar.id):
  3278. items.append((bar.id, bar.title))
  3279. self.assertEquals(items, [
  3280. (100, "Title 300"),
  3281. (200, "Title 200"),
  3282. ])
  3283. def test_indirect_reference_set_default_order_by(self):
  3284. foo = self.store.get(FooIndRefSetOrderTitle, 20)
  3285. items = []
  3286. for bar in foo.bars:
  3287. items.append((bar.id, bar.title))
  3288. self.assertEquals(items, [
  3289. (200, "Title 200"),
  3290. (100, "Title 300"),
  3291. ])
  3292. del items[:]
  3293. for bar in foo.bars.find():
  3294. items.append((bar.id, bar.title))
  3295. self.assertEquals(items, [
  3296. (200, "Title 200"),
  3297. (100, "Title 300"),
  3298. ])
  3299. foo = self.store.get(FooIndRefSetOrderID, 20)
  3300. del items[:]
  3301. for bar in foo.bars:
  3302. items.append((bar.id, bar.title))
  3303. self.assertEquals(items, [
  3304. (100, "Title 300"),
  3305. (200, "Title 200"),
  3306. ])
  3307. del items[:]
  3308. for bar in foo.bars.find():
  3309. items.append((bar.id, bar.title))
  3310. self.assertEquals(items, [
  3311. (100, "Title 300"),
  3312. (200, "Title 200"),
  3313. ])
  3314. def test_indirect_reference_set_first_last(self):
  3315. foo = self.store.get(FooIndRefSetOrderID, 20)
  3316. self.assertEquals(foo.bars.first().id, 100)
  3317. self.assertEquals(foo.bars.last().id, 200)
  3318. foo = self.store.get(FooIndRefSetOrderTitle, 20)
  3319. self.assertEquals(foo.bars.first().id, 200)
  3320. self.assertEquals(foo.bars.last().id, 100)
  3321. foo = self.store.get(FooIndRefSetOrderTitle, 20)
  3322. self.assertEquals(foo.bars.first(Bar.id > 200), None)
  3323. self.assertEquals(foo.bars.last(Bar.id > 200), None)
  3324. foo = self.store.get(FooIndRefSetOrderTitle, 20)
  3325. self.assertEquals(foo.bars.first(Bar.id < 200).id, 100)
  3326. self.assertEquals(foo.bars.last(Bar.id < 200).id, 100)
  3327. foo = self.store.get(FooIndRefSetOrderTitle, 20)
  3328. self.assertEquals(foo.bars.first(id=200).id, 200)
  3329. self.assertEquals(foo.bars.last(id=200).id, 200)
  3330. foo = self.store.get(FooIndRefSet, 20)
  3331. self.assertRaises(UnorderedError, foo.bars.first)
  3332. self.assertRaises(UnorderedError, foo.bars.last)
  3333. def test_indirect_reference_set_any(self):
  3334. """
  3335. L{BoundIndirectReferenceSet.any} returns an arbitrary object from the
  3336. set of referenced objects.
  3337. """
  3338. foo = self.store.get(FooIndRefSet, 20)
  3339. self.assertNotEqual(None, foo.bars.any())
  3340. def test_indirect_reference_set_any_filtered(self):
  3341. """
  3342. L{BoundIndirectReferenceSet.any} optionally takes a list of filtering
  3343. criteria to narrow the set of objects to search. When provided, the
  3344. criteria are used to filter the set before returning an arbitrary
  3345. object.
  3346. """
  3347. foo = self.store.get(FooIndRefSetOrderTitle, 20)
  3348. self.assertEquals(foo.bars.any(Bar.id > 200), None)
  3349. foo = self.store.get(FooIndRefSetOrderTitle, 20)
  3350. self.assertEquals(foo.bars.any(Bar.id < 200).id, 100)
  3351. foo = self.store.get(FooIndRefSetOrderTitle, 20)
  3352. self.assertEquals(foo.bars.any(id=200).id, 200)
  3353. def test_indirect_reference_set_one(self):
  3354. foo = self.store.get(FooIndRefSetOrderID, 20)
  3355. self.assertRaises(NotOneError, foo.bars.one)
  3356. foo = self.store.get(FooIndRefSetOrderID, 30)
  3357. self.assertEquals(foo.bars.one().id, 300)
  3358. foo = self.store.get(FooIndRefSetOrderID, 20)
  3359. self.assertEquals(foo.bars.one(Bar.id > 200), None)
  3360. foo = self.store.get(FooIndRefSetOrderID, 20)
  3361. self.assertEquals(foo.bars.one(Bar.id < 200).id, 100)
  3362. foo = self.store.get(FooIndRefSetOrderID, 20)
  3363. self.assertEquals(foo.bars.one(id=200).id, 200)
  3364. def test_indirect_reference_set_add(self):
  3365. foo = self.store.get(FooIndRefSet, 20)
  3366. bar = self.store.get(Bar, 300)
  3367. foo.bars.add(bar)
  3368. items = []
  3369. for bar in foo.bars:
  3370. items.append((bar.id, bar.title))
  3371. items.sort()
  3372. self.assertEquals(items, [
  3373. (100, "Title 300"),
  3374. (200, "Title 200"),
  3375. (300, "Title 100"),
  3376. ])
  3377. def test_indirect_reference_set_remove(self):
  3378. foo = self.store.get(FooIndRefSet, 20)
  3379. bar = self.store.get(Bar, 200)
  3380. foo.bars.remove(bar)
  3381. items = []
  3382. for bar in foo.bars:
  3383. items.append((bar.id, bar.title))
  3384. items.sort()
  3385. self.assertEquals(items, [
  3386. (100, "Title 300"),
  3387. ])
  3388. def test_indirect_reference_set_add_remove(self):
  3389. foo = self.store.get(FooIndRefSet, 20)
  3390. bar = self.store.get(Bar, 300)
  3391. foo.bars.add(bar)
  3392. foo.bars.remove(bar)
  3393. items = []
  3394. for bar in foo.bars:
  3395. items.append((bar.id, bar.title))
  3396. items.sort()
  3397. self.assertEquals(items, [
  3398. (100, "Title 300"),
  3399. (200, "Title 200"),
  3400. ])
  3401. def test_indirect_reference_set_add_remove_with_wrapper(self):
  3402. foo = self.store.get(FooIndRefSet, 20)
  3403. bar300 = self.store.get(Bar, 300)
  3404. bar200 = self.store.get(Bar, 200)
  3405. foo.bars.add(Wrapper(bar300))
  3406. foo.bars.remove(Wrapper(bar200))
  3407. items = []
  3408. for bar in foo.bars:
  3409. items.append((bar.id, bar.title))
  3410. items.sort()
  3411. self.assertEquals(items, [
  3412. (100, "Title 300"),
  3413. (300, "Title 100"),
  3414. ])
  3415. def test_indirect_reference_set_add_remove_with_added(self):
  3416. foo = FooIndRefSet()
  3417. foo.id = 40
  3418. bar1 = Bar()
  3419. bar1.id = 400
  3420. bar1.title = u"Title 400"
  3421. bar2 = Bar()
  3422. bar2.id = 500
  3423. bar2.title = u"Title 500"
  3424. self.store.add(foo)
  3425. self.store.add(bar1)
  3426. self.store.add(bar2)
  3427. foo.bars.add(bar1)
  3428. foo.bars.add(bar2)
  3429. foo.bars.remove(bar1)
  3430. items = []
  3431. for bar in foo.bars:
  3432. items.append((bar.id, bar.title))
  3433. items.sort()
  3434. self.assertEquals(items, [
  3435. (500, "Title 500"),
  3436. ])
  3437. def test_indirect_reference_set_with_added_no_store(self):
  3438. bar1 = Bar()
  3439. bar1.id = 400
  3440. bar1.title = u"Title 400"
  3441. bar2 = Bar()
  3442. bar2.id = 500
  3443. bar2.title = u"Title 500"
  3444. foo = FooIndRefSet()
  3445. foo.title = u"Title 40"
  3446. foo.bars.add(bar1)
  3447. foo.bars.add(bar2)
  3448. self.store.add(bar1)
  3449. self.assertEquals(Store.of(foo), self.store)
  3450. self.assertEquals(Store.of(bar1), self.store)
  3451. self.assertEquals(Store.of(bar2), self.store)
  3452. self.assertEquals(foo.id, None)
  3453. self.assertEquals(bar1.foo_id, None)
  3454. self.assertEquals(bar2.foo_id, None)
  3455. self.assertEquals(list(foo.bars.order_by(Bar.id)),
  3456. [bar1, bar2])
  3457. def test_indirect_reference_set_values(self):
  3458. foo = self.store.get(FooIndRefSetOrderID, 20)
  3459. values = list(foo.bars.values(Bar.id, Bar.foo_id, Bar.title))
  3460. self.assertEquals(values, [
  3461. (100, 10, "Title 300"),
  3462. (200, 20, "Title 200"),
  3463. ])
  3464. def test_references_raise_nostore(self):
  3465. foo1 = FooRefSet()
  3466. foo2 = FooIndRefSet()
  3467. self.assertRaises(NoStoreError, foo1.bars.__iter__)
  3468. self.assertRaises(NoStoreError, foo2.bars.__iter__)
  3469. self.assertRaises(NoStoreError, foo1.bars.find)
  3470. self.assertRaises(NoStoreError, foo2.bars.find)
  3471. self.assertRaises(NoStoreError, foo1.bars.order_by)
  3472. self.assertRaises(NoStoreError, foo2.bars.order_by)
  3473. self.assertRaises(NoStoreError, foo1.bars.count)
  3474. self.assertRaises(NoStoreError, foo2.bars.count)
  3475. self.assertRaises(NoStoreError, foo1.bars.clear)
  3476. self.assertRaises(NoStoreError, foo2.bars.clear)
  3477. self.assertRaises(NoStoreError, foo2.bars.remove, object())
  3478. def test_string_reference(self):
  3479. class Base(object):
  3480. __metaclass__ = PropertyPublisherMeta
  3481. class MyBar(Base):
  3482. __storm_table__ = "bar"
  3483. id = Int(primary=True)
  3484. title = Unicode()
  3485. foo_id = Int()
  3486. foo = Reference("foo_id", "MyFoo.id")
  3487. class MyFoo(Base):
  3488. __storm_table__ = "foo"
  3489. id = Int(primary=True)
  3490. title = Unicode()
  3491. bar = self.store.get(MyBar, 100)
  3492. self.assertTrue(bar.foo)
  3493. self.assertEquals(bar.foo.title, "Title 30")
  3494. self.assertEquals(type(bar.foo), MyFoo)
  3495. def test_string_indirect_reference_set(self):
  3496. """
  3497. A L{ReferenceSet} can have its reference keys specified as strings
  3498. when the class its a member of uses the L{PropertyPublisherMeta}
  3499. metaclass. This makes it possible to work around problems with
  3500. circular dependencies by delaying property resolution.
  3501. """
  3502. class Base(object):
  3503. __metaclass__ = PropertyPublisherMeta
  3504. class MyFoo(Base):
  3505. __storm_table__ = "foo"
  3506. id = Int(primary=True)
  3507. title = Unicode()
  3508. bars = ReferenceSet("id", "MyLink.foo_id",
  3509. "MyLink.bar_id", "MyBar.id")
  3510. class MyBar(Base):
  3511. __storm_table__ = "bar"
  3512. id = Int(primary=True)
  3513. title = Unicode()
  3514. class MyLink(Base):
  3515. __storm_table__ = "link"
  3516. __storm_primary__ = "foo_id", "bar_id"
  3517. foo_id = Int()
  3518. bar_id = Int()
  3519. foo = self.store.get(MyFoo, 20)
  3520. items = []
  3521. for bar in foo.bars:
  3522. items.append((bar.id, bar.title))
  3523. items.sort()
  3524. self.assertEquals(items, [
  3525. (100, "Title 300"),
  3526. (200, "Title 200"),
  3527. ])
  3528. def test_string_reference_set_order_by(self):
  3529. """
  3530. A L{ReferenceSet} can have its default order by specified as a string
  3531. when the class its a member of uses the L{PropertyPublisherMeta}
  3532. metaclass. This makes it possible to work around problems with
  3533. circular dependencies by delaying resolution of the order by column.
  3534. """
  3535. class Base(object):
  3536. __metaclass__ = PropertyPublisherMeta
  3537. class MyFoo(Base):
  3538. __storm_table__ = "foo"
  3539. id = Int(primary=True)
  3540. title = Unicode()
  3541. bars = ReferenceSet("id", "MyLink.foo_id",
  3542. "MyLink.bar_id", "MyBar.id",
  3543. order_by="MyBar.title")
  3544. class MyBar(Base):
  3545. __storm_table__ = "bar"
  3546. id = Int(primary=True)
  3547. title = Unicode()
  3548. class MyLink(Base):
  3549. __storm_table__ = "link"
  3550. __storm_primary__ = "foo_id", "bar_id"
  3551. foo_id = Int()
  3552. bar_id = Int()
  3553. foo = self.store.get(MyFoo, 20)
  3554. items = [(bar.id, bar.title) for bar in foo.bars]
  3555. self.assertEquals(items, [(200, "Title 200"), (100, "Title 300")])
  3556. def test_flush_order(self):
  3557. foo1 = Foo()
  3558. foo2 = Foo()
  3559. foo3 = Foo()
  3560. foo4 = Foo()
  3561. foo5 = Foo()
  3562. for i, foo in enumerate([foo1, foo2, foo3, foo4, foo5]):
  3563. foo.title = u"Object %d" % (i+1)
  3564. self.store.add(foo)
  3565. self.store.add_flush_order(foo2, foo4)
  3566. self.store.add_flush_order(foo4, foo1)
  3567. self.store.add_flush_order(foo1, foo3)
  3568. self.store.add_flush_order(foo3, foo5)
  3569. self.store.add_flush_order(foo5, foo2)
  3570. self.store.add_flush_order(foo5, foo2)
  3571. self.assertRaises(OrderLoopError, self.store.flush)
  3572. self.store.remove_flush_order(foo5, foo2)
  3573. self.assertRaises(OrderLoopError, self.store.flush)
  3574. self.store.remove_flush_order(foo5, foo2)
  3575. self.store.flush()
  3576. self.assertTrue(foo2.id < foo4.id)
  3577. self.assertTrue(foo4.id < foo1.id)
  3578. self.assertTrue(foo1.id < foo3.id)
  3579. self.assertTrue(foo3.id < foo5.id)
  3580. def test_variable_filter_on_load(self):
  3581. foo = self.store.get(FooVariable, 20)
  3582. self.assertEquals(foo.title, "to_py(from_db(Title 20))")
  3583. def test_variable_filter_on_update(self):
  3584. foo = self.store.get(FooVariable, 20)
  3585. foo.title = u"Title 20"
  3586. self.store.flush()
  3587. self.assertEquals(self.get_items(), [
  3588. (10, "Title 30"),
  3589. (20, "to_db(from_py(Title 20))"),
  3590. (30, "Title 10"),
  3591. ])
  3592. def test_variable_filter_on_update_unchanged(self):
  3593. foo = self.store.get(FooVariable, 20)
  3594. self.store.flush()
  3595. self.assertEquals(self.get_items(), [
  3596. (10, "Title 30"),
  3597. (20, "Title 20"),
  3598. (30, "Title 10"),
  3599. ])
  3600. def test_variable_filter_on_insert(self):
  3601. foo = FooVariable()
  3602. foo.id = 40
  3603. foo.title = u"Title 40"
  3604. self.store.add(foo)
  3605. self.store.flush()
  3606. self.assertEquals(self.get_items(), [
  3607. (10, "Title 30"),
  3608. (20, "Title 20"),
  3609. (30, "Title 10"),
  3610. (40, "to_db(from_py(Title 40))"),
  3611. ])
  3612. def test_variable_filter_on_missing_values(self):
  3613. foo = FooVariable()
  3614. foo.id = 40
  3615. self.store.add(foo)
  3616. self.store.flush()
  3617. self.assertEquals(foo.title, "to_py(from_db(Default Title))")
  3618. def test_variable_filter_on_set(self):
  3619. foo = FooVariable()
  3620. self.store.find(FooVariable, id=20).set(title=u"Title 20")
  3621. self.assertEquals(self.get_items(), [
  3622. (10, "Title 30"),
  3623. (20, "to_db(from_py(Title 20))"),
  3624. (30, "Title 10"),
  3625. ])
  3626. def test_variable_filter_on_set_expr(self):
  3627. foo = FooVariable()
  3628. result = self.store.find(FooVariable, id=20)
  3629. result.set(FooVariable.title == u"Title 20")
  3630. self.assertEquals(self.get_items(), [
  3631. (10, "Title 30"),
  3632. (20, "to_db(from_py(Title 20))"),
  3633. (30, "Title 10"),
  3634. ])
  3635. def test_wb_result_set_variable(self):
  3636. Result = self.store._connection.result_factory
  3637. class MyResult(Result):
  3638. def set_variable(self, variable, value):
  3639. if variable.__class__ is UnicodeVariable:
  3640. variable.set(u"set_variable(%s)" % value)
  3641. elif variable.__class__ is IntVariable:
  3642. variable.set(value+1)
  3643. else:
  3644. variable.set(value)
  3645. self.store._connection.result_factory = MyResult
  3646. try:
  3647. foo = self.store.get(Foo, 20)
  3648. finally:
  3649. self.store._connection.result_factory = Result
  3650. self.assertEquals(foo.id, 21)
  3651. self.assertEquals(foo.title, "set_variable(Title 20)")
  3652. def test_default(self):
  3653. class MyFoo(Foo):
  3654. title = Unicode(default=u"Some default value")
  3655. foo = MyFoo()
  3656. self.store.add(foo)
  3657. self.store.flush()
  3658. result = self.store.execute("SELECT title FROM foo WHERE id=?",
  3659. (foo.id,))
  3660. self.assertEquals(result.get_one(), ("Some default value",))
  3661. self.assertEquals(foo.title, "Some default value")
  3662. def test_default_factory(self):
  3663. class MyFoo(Foo):
  3664. title = Unicode(default_factory=lambda:u"Some default value")
  3665. foo = MyFoo()
  3666. self.store.add(foo)
  3667. self.store.flush()
  3668. result = self.store.execute("SELECT title FROM foo WHERE id=?",
  3669. (foo.id,))
  3670. self.assertEquals(result.get_one(), ("Some default value",))
  3671. self.assertEquals(foo.title, "Some default value")
  3672. def test_pickle_variable(self):
  3673. class PickleBlob(Blob):
  3674. bin = Pickle()
  3675. blob = self.store.get(Blob, 20)
  3676. blob.bin = "\x80\x02}q\x01U\x01aK\x01s."
  3677. self.store.flush()
  3678. pickle_blob = self.store.get(PickleBlob, 20)
  3679. self.assertEquals(pickle_blob.bin["a"], 1)
  3680. pickle_blob.bin["b"] = 2
  3681. self.store.flush()
  3682. self.store.reload(blob)
  3683. self.assertEquals(blob.bin, "\x80\x02}q\x01(U\x01aK\x01U\x01bK\x02u.")
  3684. def test_pickle_variable_remove(self):
  3685. """
  3686. When an object is removed from a store, it should unhook from the
  3687. "flush" event emitted by the store, and thus not emit a "changed" event
  3688. if its content change and that the store is flushed.
  3689. """
  3690. class PickleBlob(Blob):
  3691. bin = Pickle()
  3692. blob = self.store.get(Blob, 20)
  3693. blob.bin = "\x80\x02}q\x01U\x01aK\x01s."
  3694. self.store.flush()
  3695. pickle_blob = self.store.get(PickleBlob, 20)
  3696. self.store.remove(pickle_blob)
  3697. self.store.flush()
  3698. # Let's change the object
  3699. pickle_blob.bin = "foobin"
  3700. # And subscribe to its changed event
  3701. obj_info = get_obj_info(pickle_blob)
  3702. events = []
  3703. obj_info.event.hook("changed", lambda *args: events.append(args))
  3704. self.store.flush()
  3705. self.assertEquals(events, [])
  3706. def test_pickle_variable_unhook(self):
  3707. """
  3708. A variable instance must unhook itself from the store event system when
  3709. the store invalidates its objects.
  3710. """
  3711. # I create a custom PickleVariable, with no __slots__ definition, to be
  3712. # able to get a weakref of it, thing that I can't do with
  3713. # PickleVariable that defines __slots__ *AND* those parent is the C
  3714. # implementation of Variable
  3715. class CustomPickleVariable(PickleVariable):
  3716. pass
  3717. class CustomPickle(Pickle):
  3718. variable_class = CustomPickleVariable
  3719. class PickleBlob(Blob):
  3720. bin = CustomPickle()
  3721. blob = self.store.get(Blob, 20)
  3722. blob.bin = "\x80\x02}q\x01U\x01aK\x01s."
  3723. self.store.flush()
  3724. pickle_blob = self.store.get(PickleBlob, 20)
  3725. self.store.flush()
  3726. self.store.invalidate()
  3727. obj_info = get_obj_info(pickle_blob)
  3728. variable = obj_info.variables[PickleBlob.bin]
  3729. var_ref = weakref.ref(variable)
  3730. del variable, blob, pickle_blob, obj_info
  3731. gc.collect()
  3732. self.assertTrue(var_ref() is None)
  3733. def test_pickle_variable_referenceset(self):
  3734. """
  3735. A variable instance must unhook itself from the store event system
  3736. explcitely when the store invalidates its objects: it's particulary
  3737. important when a ReferenceSet is used, because it keeps strong
  3738. references to objects involved.
  3739. """
  3740. class CustomPickleVariable(PickleVariable):
  3741. pass
  3742. class CustomPickle(Pickle):
  3743. variable_class = CustomPickleVariable
  3744. class PickleBlob(Blob):
  3745. bin = CustomPickle()
  3746. foo_id = Int()
  3747. class FooBlobRefSet(Foo):
  3748. blobs = ReferenceSet(Foo.id, PickleBlob.foo_id)
  3749. blob = self.store.get(Blob, 20)
  3750. blob.bin = "\x80\x02}q\x01U\x01aK\x01s."
  3751. self.store.flush()
  3752. pickle_blob = self.store.get(PickleBlob, 20)
  3753. foo = self.store.get(FooBlobRefSet, 10)
  3754. foo.blobs.add(pickle_blob)
  3755. self.store.flush()
  3756. self.store.invalidate()
  3757. obj_info = get_obj_info(pickle_blob)
  3758. variable = obj_info.variables[PickleBlob.bin]
  3759. var_ref = weakref.ref(variable)
  3760. del variable, blob, pickle_blob, obj_info, foo
  3761. gc.collect()
  3762. self.assertTrue(var_ref() is None)
  3763. def test_pickle_variable_referenceset_several_transactions(self):
  3764. """
  3765. Check that a pickle variable fires the changed event when used among
  3766. several transactions.
  3767. """
  3768. class PickleBlob(Blob):
  3769. bin = Pickle()
  3770. foo_id = Int()
  3771. class FooBlobRefSet(Foo):
  3772. blobs = ReferenceSet(Foo.id, PickleBlob.foo_id)
  3773. blob = self.store.get(Blob, 20)
  3774. blob.bin = "\x80\x02}q\x01U\x01aK\x01s."
  3775. self.store.flush()
  3776. pickle_blob = self.store.get(PickleBlob, 20)
  3777. foo = self.store.get(FooBlobRefSet, 10)
  3778. foo.blobs.add(pickle_blob)
  3779. self.store.flush()
  3780. self.store.invalidate()
  3781. self.store.reload(pickle_blob)
  3782. pickle_blob.bin = "foo"
  3783. obj_info = get_obj_info(pickle_blob)
  3784. events = []
  3785. obj_info.event.hook("changed", lambda *args: events.append(args))
  3786. self.store.flush()
  3787. self.assertEquals(len(events), 1)
  3788. def test_undefined_variables_filled_on_find(self):
  3789. """
  3790. Check that when data is fetched from the database on a find,
  3791. it is used to fill up any undefined variables.
  3792. """
  3793. # We do a first find to get the object_infos into the cache.
  3794. foos = list(self.store.find(Foo, title=u"Title 20"))
  3795. # Commit so that all foos are invalidated and variables are
  3796. # set back to AutoReload.
  3797. self.store.commit()
  3798. # Another find which should reuse in-memory foos.
  3799. for foo in self.store.find(Foo, title=u"Title 20"):
  3800. # Make sure we have all variables defined, because
  3801. # values were already retrieved by the find's select.
  3802. obj_info = get_obj_info(foo)
  3803. for column in obj_info.variables:
  3804. self.assertTrue(obj_info.variables[column].is_defined())
  3805. def test_storm_loaded_after_define(self):
  3806. """
  3807. C{__storm_loaded__} is only called once all the variables are correctly
  3808. defined in the object. If the object is in the alive cache but
  3809. disappeared, it used to be called without its variables defined.
  3810. """
  3811. # Disable the cache, which holds strong references.
  3812. self.get_cache(self.store).set_size(0)
  3813. loaded = []
  3814. class MyFoo(Foo):
  3815. def __storm_loaded__(oself):
  3816. loaded.append(None)
  3817. obj_info = get_obj_info(oself)
  3818. for column in obj_info.variables:
  3819. self.assertTrue(obj_info.variables[column].is_defined())
  3820. foo = self.store.get(MyFoo, 20)
  3821. obj_info = get_obj_info(foo)
  3822. del foo
  3823. gc.collect()
  3824. self.assertEquals(obj_info.get_obj(), None)
  3825. # Commit so that all foos are invalidated and variables are
  3826. # set back to AutoReload.
  3827. self.store.commit()
  3828. foo = self.store.find(MyFoo, title=u"Title 20").one()
  3829. self.assertEquals(foo.id, 20)
  3830. self.assertEquals(len(loaded), 2)
  3831. def test_defined_variables_not_overridden_on_find(self):
  3832. """
  3833. Check that the keep_defined=True setting in _load_object()
  3834. is in place. In practice, it ensures that already defined
  3835. values aren't replaced during a find, when new data comes
  3836. from the database and is used whenever possible.
  3837. """
  3838. blob = self.store.get(Blob, 20)
  3839. blob.bin = "\x80\x02}q\x01U\x01aK\x01s."
  3840. class PickleBlob(object):
  3841. __storm_table__ = "bin"
  3842. id = Int(primary=True)
  3843. pickle = Pickle("bin")
  3844. blob = self.store.get(PickleBlob, 20)
  3845. value = blob.pickle
  3846. # Now the find should not destroy our value pointer.
  3847. blob = self.store.find(PickleBlob, id=20).one()
  3848. self.assertTrue(value is blob.pickle)
  3849. def test_pickle_variable_with_deleted_object(self):
  3850. class PickleBlob(Blob):
  3851. bin = Pickle()
  3852. blob = self.store.get(Blob, 20)
  3853. blob.bin = "\x80\x02}q\x01U\x01aK\x01s."
  3854. self.store.flush()
  3855. pickle_blob = self.store.get(PickleBlob, 20)
  3856. self.assertEquals(pickle_blob.bin["a"], 1)
  3857. pickle_blob.bin["b"] = 2
  3858. del pickle_blob
  3859. gc.collect()
  3860. self.store.flush()
  3861. self.store.reload(blob)
  3862. self.assertEquals(blob.bin, "\x80\x02}q\x01(U\x01aK\x01U\x01bK\x02u.")
  3863. def test_unhashable_object(self):
  3864. class DictFoo(Foo, dict):
  3865. pass
  3866. foo = self.store.get(DictFoo, 20)
  3867. foo["a"] = 1
  3868. self.assertEquals(foo.items(), [("a", 1)])
  3869. new_obj = DictFoo()
  3870. new_obj.id = 40
  3871. new_obj.title = u"My Title"
  3872. self.store.add(new_obj)
  3873. self.store.commit()
  3874. self.assertTrue(self.store.get(DictFoo, 40) is new_obj)
  3875. def test_wrapper(self):
  3876. foo = self.store.get(Foo, 20)
  3877. wrapper = Wrapper(foo)
  3878. self.store.remove(wrapper)
  3879. self.store.flush()
  3880. self.assertEquals(self.store.get(Foo, 20), None)
  3881. def test_rollback_loaded_and_still_in_cached(self):
  3882. # Explore problem found on interaction between caching, commits,
  3883. # and rollbacks, when they still existed.
  3884. foo1 = self.store.get(Foo, 20)
  3885. self.store.commit()
  3886. self.store.rollback()
  3887. foo2 = self.store.get(Foo, 20)
  3888. self.assertTrue(foo1 is foo2)
  3889. def test_class_alias(self):
  3890. FooAlias = ClassAlias(Foo)
  3891. result = self.store.find(FooAlias, FooAlias.id < Foo.id)
  3892. self.assertEquals([(foo.id, foo.title) for foo in result
  3893. if type(foo) is Foo], [
  3894. (10, "Title 30"),
  3895. (10, "Title 30"),
  3896. (20, "Title 20"),
  3897. ])
  3898. def test_expr_values(self):
  3899. foo = self.store.get(Foo, 20)
  3900. foo.title = SQL("'New title'")
  3901. # No commits yet.
  3902. self.assertEquals(self.get_items(), [
  3903. (10, "Title 30"),
  3904. (20, "Title 20"),
  3905. (30, "Title 10"),
  3906. ])
  3907. self.store.flush()
  3908. # Now it should be there.
  3909. self.assertEquals(self.get_items(), [
  3910. (10, "Title 30"),
  3911. (20, "New title"),
  3912. (30, "Title 10"),
  3913. ])
  3914. self.assertEquals(foo.title, "New title")
  3915. def test_expr_values_flush_on_demand(self):
  3916. foo = self.store.get(Foo, 20)
  3917. foo.title = SQL("'New title'")
  3918. # No commits yet.
  3919. self.assertEquals(self.get_items(), [
  3920. (10, "Title 30"),
  3921. (20, "Title 20"),
  3922. (30, "Title 10"),
  3923. ])
  3924. self.assertEquals(foo.title, "New title")
  3925. # Now it should be there.
  3926. self.assertEquals(self.get_items(), [
  3927. (10, "Title 30"),
  3928. (20, "New title"),
  3929. (30, "Title 10"),
  3930. ])
  3931. def test_expr_values_flush_and_load_in_separate_steps(self):
  3932. foo = self.store.get(Foo, 20)
  3933. foo.title = SQL("'New title'")
  3934. self.store.flush()
  3935. # It's already in the database.
  3936. self.assertEquals(self.get_items(), [
  3937. (10, "Title 30"),
  3938. (20, "New title"),
  3939. (30, "Title 10"),
  3940. ])
  3941. # But our value is now an AutoReload.
  3942. lazy_value = get_obj_info(foo).variables[Foo.title].get_lazy()
  3943. self.assertTrue(lazy_value is AutoReload)
  3944. # Which gets resolved once touched.
  3945. self.assertEquals(foo.title, u"New title")
  3946. def test_expr_values_flush_on_demand_with_added(self):
  3947. foo = Foo()
  3948. foo.id = 40
  3949. foo.title = SQL("'New title'")
  3950. self.store.add(foo)
  3951. # No commits yet.
  3952. self.assertEquals(self.get_items(), [
  3953. (10, "Title 30"),
  3954. (20, "Title 20"),
  3955. (30, "Title 10"),
  3956. ])
  3957. self.assertEquals(foo.title, "New title")
  3958. # Now it should be there.
  3959. self.assertEquals(self.get_items(), [
  3960. (10, "Title 30"),
  3961. (20, "Title 20"),
  3962. (30, "Title 10"),
  3963. (40, "New title"),
  3964. ])
  3965. def test_expr_values_flush_on_demand_with_removed_and_added(self):
  3966. foo = self.store.get(Foo, 20)
  3967. foo.title = SQL("'New title'")
  3968. self.store.remove(foo)
  3969. self.store.add(foo)
  3970. # No commits yet.
  3971. self.assertEquals(self.get_items(), [
  3972. (10, "Title 30"),
  3973. (20, "Title 20"),
  3974. (30, "Title 10"),
  3975. ])
  3976. self.assertEquals(foo.title, "New title")
  3977. # Now it should be there.
  3978. self.assertEquals(self.get_items(), [
  3979. (10, "Title 30"),
  3980. (20, "New title"),
  3981. (30, "Title 10"),
  3982. ])
  3983. def test_expr_values_flush_on_demand_with_removed_and_rollbacked(self):
  3984. foo = self.store.get(Foo, 20)
  3985. self.store.remove(foo)
  3986. self.store.rollback()
  3987. foo.title = SQL("'New title'")
  3988. # No commits yet.
  3989. self.assertEquals(self.get_items(), [
  3990. (10, "Title 30"),
  3991. (20, "Title 20"),
  3992. (30, "Title 10"),
  3993. ])
  3994. self.assertEquals(foo.title, "New title")
  3995. # Now it should be there.
  3996. self.assertEquals(self.get_items(), [
  3997. (10, "Title 30"),
  3998. (20, "New title"),
  3999. (30, "Title 10"),
  4000. ])
  4001. def test_expr_values_flush_on_demand_with_added_and_removed(self):
  4002. # This test tries to trigger a problem in a few different ways.
  4003. # It uses the same id of an existing object, and add and remove
  4004. # the object. This object should never get in the database, nor
  4005. # update the object that is already there, nor flush any other
  4006. # pending changes when the lazy value is accessed.
  4007. foo = Foo()
  4008. foo.id = 20
  4009. foo_dep = Foo()
  4010. foo_dep.id = 50
  4011. self.store.add(foo)
  4012. self.store.add(foo_dep)
  4013. foo.title = SQL("'New title'")
  4014. # Add ordering to see if it helps triggering a bug of
  4015. # incorrect flushing.
  4016. self.store.add_flush_order(foo_dep, foo)
  4017. self.store.remove(foo)
  4018. # No changes.
  4019. self.assertEquals(self.get_items(), [
  4020. (10, "Title 30"),
  4021. (20, "Title 20"),
  4022. (30, "Title 10"),
  4023. ])
  4024. self.assertEquals(foo.title, None)
  4025. # Still no changes. There's no reason why foo_dep would be flushed.
  4026. self.assertEquals(self.get_items(), [
  4027. (10, "Title 30"),
  4028. (20, "Title 20"),
  4029. (30, "Title 10"),
  4030. ])
  4031. def test_expr_values_flush_on_demand_with_removed(self):
  4032. # Similar case, but removing an existing object instead.
  4033. foo = self.store.get(Foo, 20)
  4034. foo_dep = Foo()
  4035. foo_dep.id = 50
  4036. self.store.add(foo_dep)
  4037. foo.title = SQL("'New title'")
  4038. # Add ordering to see if it helps triggering a bug of
  4039. # incorrect flushing.
  4040. self.store.add_flush_order(foo_dep, foo)
  4041. self.store.remove(foo)
  4042. # No changes.
  4043. self.assertEquals(self.get_items(), [
  4044. (10, "Title 30"),
  4045. (20, "Title 20"),
  4046. (30, "Title 10"),
  4047. ])
  4048. self.assertEquals(foo.title, None)
  4049. # Still no changes. There's no reason why foo_dep would be flushed.
  4050. self.assertEquals(self.get_items(), [
  4051. (10, "Title 30"),
  4052. (20, "Title 20"),
  4053. (30, "Title 10"),
  4054. ])
  4055. def test_lazy_value_preserved_with_subsequent_object_initialization(self):
  4056. """
  4057. If a lazy value has been modified on an object that is subsequently
  4058. initialized from the database the lazy value is correctly preserved
  4059. and the object is initialized properly. This tests the fix for the
  4060. problem reported in bug #620615.
  4061. """
  4062. # Retrieve an object, fully loaded.
  4063. foo = self.store.get(Foo, 20)
  4064. # Build and retrieve a result set ahead of time, so that
  4065. # flushes won't happen when actually loading the object.
  4066. result = self.store.find(Foo, Foo.id == 20)
  4067. # Now, set an unflushed lazy value on an attribute.
  4068. foo.title = SQL("'New title'")
  4069. # Finally, get the existing object.
  4070. foo = result.one()
  4071. # We don't really have to test anything here, since the
  4072. # explosion happened above, but here it is anyway.
  4073. self.assertEquals(foo.title, "New title")
  4074. def test_lazy_value_discarded_on_reload(self):
  4075. """
  4076. A counter-test to the above logic, also related to bug #620615. On
  4077. an explicit reload, the lazy value must be discarded.
  4078. """
  4079. # Retrieve an object, fully loaded.
  4080. foo = self.store.get(Foo, 20)
  4081. # Build and retrieve a result set ahead of time, so that
  4082. # flushes won't happen when actually loading the object.
  4083. result = self.store.find(Foo, Foo.id == 20)
  4084. # Now, set an unflushed lazy value on an attribute.
  4085. foo.title = SQL("'New title'")
  4086. # Give up on this and reload the original object.
  4087. self.store.reload(foo)
  4088. # We don't really have to test anything here, since the
  4089. # explosion happened above, but here it is anyway.
  4090. self.assertEquals(foo.title, "Title 20")
  4091. def test_expr_values_with_columns(self):
  4092. bar = self.store.get(Bar, 200)
  4093. bar.foo_id = Bar.id+1
  4094. self.assertEquals(bar.foo_id, 201)
  4095. def test_autoreload_attribute(self):
  4096. foo = self.store.get(Foo, 20)
  4097. self.store.execute("UPDATE foo SET title='New Title' WHERE id=20")
  4098. self.assertEquals(foo.title, "Title 20")
  4099. foo.title = AutoReload
  4100. self.assertEquals(foo.title, "New Title")
  4101. self.assertFalse(get_obj_info(foo).variables[Foo.title].has_changed())
  4102. def test_autoreload_attribute_with_changed_primary_key(self):
  4103. foo = self.store.get(Foo, 20)
  4104. self.store.execute("UPDATE foo SET title='New Title' WHERE id=20")
  4105. self.assertEquals(foo.title, "Title 20")
  4106. foo.id = 40
  4107. foo.title = AutoReload
  4108. self.assertEquals(foo.title, "New Title")
  4109. self.assertEquals(foo.id, 40)
  4110. def test_autoreload_object(self):
  4111. foo = self.store.get(Foo, 20)
  4112. self.store.execute("UPDATE foo SET title='New Title' WHERE id=20")
  4113. self.assertEquals(foo.title, "Title 20")
  4114. self.store.autoreload(foo)
  4115. self.assertEquals(foo.title, "New Title")
  4116. def test_autoreload_primary_key_of_unflushed_object(self):
  4117. foo = Foo()
  4118. self.store.add(foo)
  4119. foo.id = AutoReload
  4120. foo.title = u"New Title"
  4121. self.assertTrue(isinstance(foo.id, (int, long)))
  4122. self.assertEquals(foo.title, "New Title")
  4123. def test_autoreload_primary_key_doesnt_reload_everything_else(self):
  4124. foo = self.store.get(Foo, 20)
  4125. self.store.autoreload(foo)
  4126. obj_info = get_obj_info(foo)
  4127. self.assertEquals(obj_info.variables[Foo.id].get_lazy(), None)
  4128. self.assertEquals(obj_info.variables[Foo.title].get_lazy(), AutoReload)
  4129. self.assertEquals(foo.id, 20)
  4130. self.assertEquals(obj_info.variables[Foo.id].get_lazy(), None)
  4131. self.assertEquals(obj_info.variables[Foo.title].get_lazy(), AutoReload)
  4132. def test_autoreload_all_objects(self):
  4133. foo = self.store.get(Foo, 20)
  4134. self.store.execute("UPDATE foo SET title='New Title' WHERE id=20")
  4135. self.assertEquals(foo.title, "Title 20")
  4136. self.store.autoreload()
  4137. self.assertEquals(foo.title, "New Title")
  4138. def test_autoreload_and_get_will_not_reload(self):
  4139. foo = self.store.get(Foo, 20)
  4140. self.store.execute("UPDATE foo SET title='New Title' WHERE id=20")
  4141. self.store.autoreload(foo)
  4142. obj_info = get_obj_info(foo)
  4143. self.assertEquals(obj_info.variables[Foo.title].get_lazy(), AutoReload)
  4144. self.store.get(Foo, 20)
  4145. self.assertEquals(obj_info.variables[Foo.title].get_lazy(), AutoReload)
  4146. self.assertEquals(foo.title, "New Title")
  4147. def test_autoreload_object_doesnt_tag_as_dirty(self):
  4148. foo = self.store.get(Foo, 20)
  4149. self.store.autoreload(foo)
  4150. self.assertTrue(get_obj_info(foo) not in self.store._dirty)
  4151. def test_autoreload_missing_columns_on_insertion(self):
  4152. foo = Foo()
  4153. self.store.add(foo)
  4154. self.store.flush()
  4155. lazy_value = get_obj_info(foo).variables[Foo.title].get_lazy()
  4156. self.assertEquals(lazy_value, AutoReload)
  4157. self.assertEquals(foo.title, u"Default Title")
  4158. def test_reference_break_on_local_diverged_doesnt_autoreload(self):
  4159. foo = self.store.get(Foo, 10)
  4160. self.store.autoreload(foo)
  4161. bar = self.store.get(Bar, 100)
  4162. self.assertTrue(bar.foo)
  4163. bar.foo_id = 40
  4164. self.assertEquals(bar.foo, None)
  4165. obj_info = get_obj_info(foo)
  4166. self.assertEquals(obj_info.variables[Foo.title].get_lazy(), AutoReload)
  4167. def test_primary_key_reference(self):
  4168. """
  4169. When an object references another one using its primary key, it
  4170. correctly checks for the invalidated state after the store has been
  4171. committed, detecting if the referenced object has been removed behind
  4172. its back.
  4173. """
  4174. class BarOnRemote(object):
  4175. __storm_table__ = "bar"
  4176. foo_id = Int(primary=True)
  4177. foo = Reference(foo_id, Foo.id, on_remote=True)
  4178. foo = self.store.get(Foo, 10)
  4179. bar = self.store.get(BarOnRemote, 10)
  4180. self.assertEqual(bar.foo, foo)
  4181. self.store.execute("DELETE FROM foo WHERE id = 10")
  4182. self.store.commit()
  4183. self.assertEqual(bar.foo, None)
  4184. def test_invalidate_and_get_object(self):
  4185. foo = self.store.get(Foo, 20)
  4186. self.store.invalidate(foo)
  4187. self.assertEquals(self.store.get(Foo, 20), foo)
  4188. self.assertEquals(self.store.find(Foo, id=20).one(), foo)
  4189. def test_invalidate_and_get_removed_object(self):
  4190. foo = self.store.get(Foo, 20)
  4191. self.store.execute("DELETE FROM foo WHERE id=20")
  4192. self.store.invalidate(foo)
  4193. self.assertEquals(self.store.get(Foo, 20), None)
  4194. self.assertEquals(self.store.find(Foo, id=20).one(), None)
  4195. def test_invalidate_and_validate_with_find(self):
  4196. foo = self.store.get(Foo, 20)
  4197. self.store.invalidate(foo)
  4198. self.assertEquals(self.store.find(Foo, id=20).one(), foo)
  4199. # Cache should be considered valid again at this point.
  4200. self.store.execute("DELETE FROM foo WHERE id=20")
  4201. self.assertEquals(self.store.get(Foo, 20), foo)
  4202. def test_invalidate_object_gets_validated(self):
  4203. foo = self.store.get(Foo, 20)
  4204. self.store.invalidate(foo)
  4205. self.assertEquals(self.store.get(Foo, 20), foo)
  4206. # At this point the object is valid again, so deleting it
  4207. # from the database directly shouldn't affect caching.
  4208. self.store.execute("DELETE FROM foo WHERE id=20")
  4209. self.assertEquals(self.store.get(Foo, 20), foo)
  4210. def test_invalidate_object_with_only_primary_key(self):
  4211. link = self.store.get(Link, (20, 200))
  4212. self.store.execute("DELETE FROM link WHERE foo_id=20 AND bar_id=200")
  4213. self.store.invalidate(link)
  4214. self.assertEquals(self.store.get(Link, (20, 200)), None)
  4215. def test_invalidate_added_object(self):
  4216. foo = Foo()
  4217. self.store.add(foo)
  4218. self.store.invalidate(foo)
  4219. foo.id = 40
  4220. foo.title = u"Title 40"
  4221. self.store.flush()
  4222. # Object must have a valid cache at this point, since it was
  4223. # just added.
  4224. self.store.execute("DELETE FROM foo WHERE id=40")
  4225. self.assertEquals(self.store.get(Foo, 40), foo)
  4226. def test_invalidate_and_update(self):
  4227. foo = self.store.get(Foo, 20)
  4228. self.store.execute("DELETE FROM foo WHERE id=20")
  4229. self.store.invalidate(foo)
  4230. self.assertRaises(LostObjectError, setattr, foo, "title", u"Title 40")
  4231. def test_invalidate_and_get_returns_autoreloaded(self):
  4232. foo = self.store.get(Foo, 20)
  4233. self.store.invalidate(foo)
  4234. foo = self.store.get(Foo, 20)
  4235. self.assertEquals(get_obj_info(foo).variables[Foo.title].get_lazy(),
  4236. AutoReload)
  4237. self.assertEquals(foo.title, "Title 20")
  4238. def test_invalidated_hook(self):
  4239. called = []
  4240. class MyFoo(Foo):
  4241. def __storm_invalidated__(self):
  4242. called.append(True)
  4243. foo = self.store.get(MyFoo, 20)
  4244. self.assertEquals(called, [])
  4245. self.store.autoreload(foo)
  4246. self.assertEquals(called, [])
  4247. self.store.invalidate(foo)
  4248. self.assertEquals(called, [True])
  4249. def test_invalidated_hook_called_after_all_invalidated(self):
  4250. """
  4251. Ensure that invalidated hooks are called only when all objects have
  4252. already been marked as invalidated. See comment in
  4253. store.py:_mark_autoreload.
  4254. """
  4255. called = []
  4256. class MyFoo(Foo):
  4257. def __storm_invalidated__(self):
  4258. if not called:
  4259. called.append(get_obj_info(foo1).get("invalidated"))
  4260. called.append(get_obj_info(foo2).get("invalidated"))
  4261. foo1 = self.store.get(MyFoo, 10)
  4262. foo2 = self.store.get(MyFoo, 20)
  4263. self.store.invalidate()
  4264. self.assertEquals(called, [True, True])
  4265. def test_reset_recreates_objects(self):
  4266. """
  4267. After resetting the store, all queries return fresh objects, even if
  4268. there are other objects representing the same database rows still in
  4269. memory.
  4270. """
  4271. foo1 = self.store.get(Foo, 10)
  4272. foo1.dirty = True
  4273. self.store.reset()
  4274. new_foo1 = self.store.get(Foo, 10)
  4275. self.assertFalse(hasattr(new_foo1, "dirty"))
  4276. self.assertNotIdentical(new_foo1, foo1)
  4277. def test_reset_unmarks_dirty(self):
  4278. """
  4279. If an object was dirty when store.reset() is called, its changes will
  4280. not be affected.
  4281. """
  4282. foo1 = self.store.get(Foo, 10)
  4283. foo1_title = foo1.title
  4284. foo1.title = u"radix wuz here"
  4285. self.store.reset()
  4286. self.store.flush()
  4287. new_foo1 = self.store.get(Foo, 10)
  4288. self.assertEquals(new_foo1.title, foo1_title)
  4289. def test_reset_clears_cache(self):
  4290. cache = self.get_cache(self.store)
  4291. foo1 = self.store.get(Foo, 10)
  4292. self.assertTrue(get_obj_info(foo1) in cache.get_cached())
  4293. self.store.reset()
  4294. self.assertEquals(cache.get_cached(), [])
  4295. def test_reset_breaks_store_reference(self):
  4296. """
  4297. After resetting the store, all objects that were associated with that
  4298. store will no longer be.
  4299. """
  4300. foo1 = self.store.get(Foo, 10)
  4301. self.store.reset()
  4302. self.assertIdentical(Store.of(foo1), None)
  4303. def test_result_find(self):
  4304. result1 = self.store.find(Foo, Foo.id <= 20)
  4305. result2 = result1.find(Foo.id > 10)
  4306. foo = result2.one()
  4307. self.assertTrue(foo)
  4308. self.assertEqual(foo.id, 20)
  4309. def test_result_find_kwargs(self):
  4310. result1 = self.store.find(Foo, Foo.id <= 20)
  4311. result2 = result1.find(id=20)
  4312. foo = result2.one()
  4313. self.assertTrue(foo)
  4314. self.assertEqual(foo.id, 20)
  4315. def test_result_find_introduce_join(self):
  4316. result1 = self.store.find(Foo, Foo.id <= 20)
  4317. result2 = result1.find(Foo.id == Bar.foo_id,
  4318. Bar.title == u"Title 300")
  4319. foo = result2.one()
  4320. self.assertTrue(foo)
  4321. self.assertEqual(foo.id, 10)
  4322. def test_result_find_tuple(self):
  4323. result1 = self.store.find((Foo, Bar), Foo.id == Bar.foo_id)
  4324. result2 = result1.find(Bar.title == u"Title 100")
  4325. foo_bar = result2.one()
  4326. self.assertTrue(foo_bar)
  4327. foo, bar = foo_bar
  4328. self.assertEqual(foo.id, 30)
  4329. self.assertEqual(bar.id, 300)
  4330. def test_result_find_undef_where(self):
  4331. result = self.store.find(Foo, Foo.id == 20).find()
  4332. foo = result.one()
  4333. self.assertTrue(foo)
  4334. self.assertEqual(foo.id, 20)
  4335. result = self.store.find(Foo).find(Foo.id == 20)
  4336. foo = result.one()
  4337. self.assertTrue(foo)
  4338. self.assertEqual(foo.id, 20)
  4339. def test_result_find_fails_on_set_expr(self):
  4340. result1 = self.store.find(Foo)
  4341. result2 = self.store.find(Foo)
  4342. result = result1.union(result2)
  4343. self.assertRaises(FeatureError, result.find, Foo.id == 20)
  4344. def test_result_find_fails_on_slice(self):
  4345. result = self.store.find(Foo)[1:2]
  4346. self.assertRaises(FeatureError, result.find, Foo.id == 20)
  4347. def test_result_find_fails_on_group_by(self):
  4348. result = self.store.find(Foo)
  4349. result.group_by(Foo)
  4350. self.assertRaises(FeatureError, result.find, Foo.id == 20)
  4351. def test_result_union(self):
  4352. result1 = self.store.find(Foo, id=30)
  4353. result2 = self.store.find(Foo, id=10)
  4354. result3 = result1.union(result2)
  4355. result3.order_by(Foo.title)
  4356. self.assertEquals([(foo.id, foo.title) for foo in result3], [
  4357. (30, "Title 10"),
  4358. (10, "Title 30"),
  4359. ])
  4360. result3.order_by(Desc(Foo.title))
  4361. self.assertEquals([(foo.id, foo.title) for foo in result3], [
  4362. (10, "Title 30"),
  4363. (30, "Title 10"),
  4364. ])
  4365. def test_result_union_duplicated(self):
  4366. result1 = self.store.find(Foo, id=30)
  4367. result2 = self.store.find(Foo, id=30)
  4368. result3 = result1.union(result2)
  4369. self.assertEquals([(foo.id, foo.title) for foo in result3], [
  4370. (30, "Title 10"),
  4371. ])
  4372. def test_result_union_duplicated_with_all(self):
  4373. result1 = self.store.find(Foo, id=30)
  4374. result2 = self.store.find(Foo, id=30)
  4375. result3 = result1.union(result2, all=True)
  4376. self.assertEquals([(foo.id, foo.title) for foo in result3], [
  4377. (30, "Title 10"),
  4378. (30, "Title 10"),
  4379. ])
  4380. def test_result_union_with_empty(self):
  4381. result1 = self.store.find(Foo, id=30)
  4382. result2 = EmptyResultSet()
  4383. result3 = result1.union(result2)
  4384. self.assertEquals([(foo.id, foo.title) for foo in result3], [
  4385. (30, "Title 10"),
  4386. ])
  4387. def test_result_union_unsupported_methods(self):
  4388. result1 = self.store.find(Foo, id=30)
  4389. result2 = self.store.find(Foo, id=10)
  4390. result3 = result1.union(result2)
  4391. self.assertRaises(FeatureError, result3.set, title=u"Title 40")
  4392. self.assertRaises(FeatureError, result3.remove)
  4393. def test_result_union_count(self):
  4394. result1 = self.store.find(Foo, id=30)
  4395. result2 = self.store.find(Foo, id=30)
  4396. result3 = result1.union(result2, all=True)
  4397. self.assertEquals(result3.count(), 2)
  4398. def test_result_difference(self):
  4399. if self.__class__.__name__.startswith("MySQL"):
  4400. return
  4401. result1 = self.store.find(Foo)
  4402. result2 = self.store.find(Foo, id=20)
  4403. result3 = result1.difference(result2)
  4404. result3.order_by(Foo.title)
  4405. self.assertEquals([(foo.id, foo.title) for foo in result3], [
  4406. (30, "Title 10"),
  4407. (10, "Title 30"),
  4408. ])
  4409. result3.order_by(Desc(Foo.title))
  4410. self.assertEquals([(foo.id, foo.title) for foo in result3], [
  4411. (10, "Title 30"),
  4412. (30, "Title 10"),
  4413. ])
  4414. def test_result_difference_with_empty(self):
  4415. if self.__class__.__name__.startswith("MySQL"):
  4416. return
  4417. result1 = self.store.find(Foo, id=30)
  4418. result2 = EmptyResultSet()
  4419. result3 = result1.difference(result2)
  4420. self.assertEquals([(foo.id, foo.title) for foo in result3], [
  4421. (30, "Title 10"),
  4422. ])
  4423. def test_result_difference_count(self):
  4424. if self.__class__.__name__.startswith("MySQL"):
  4425. return
  4426. result1 = self.store.find(Foo)
  4427. result2 = self.store.find(Foo, id=20)
  4428. result3 = result1.difference(result2)
  4429. self.assertEquals(result3.count(), 2)
  4430. def test_is_in_empty_result_set(self):
  4431. result1 = self.store.find(Foo, Foo.id < 10)
  4432. result2 = self.store.find(Foo, Or(Foo.id > 20, Foo.id.is_in(result1)))
  4433. self.assertEquals(result2.count(), 1)
  4434. def test_is_in_empty_list(self):
  4435. result2 = self.store.find(Foo, Eq(False, And(True, Foo.id.is_in([]))))
  4436. self.assertEquals(result2.count(), 3)
  4437. def test_result_intersection(self):
  4438. if self.__class__.__name__.startswith("MySQL"):
  4439. return
  4440. result1 = self.store.find(Foo)
  4441. result2 = self.store.find(Foo, Foo.id.is_in((10, 30)))
  4442. result3 = result1.intersection(result2)
  4443. result3.order_by(Foo.title)
  4444. self.assertEquals([(foo.id, foo.title) for foo in result3], [
  4445. (30, "Title 10"),
  4446. (10, "Title 30"),
  4447. ])
  4448. result3.order_by(Desc(Foo.title))
  4449. self.assertEquals([(foo.id, foo.title) for foo in result3], [
  4450. (10, "Title 30"),
  4451. (30, "Title 10"),
  4452. ])
  4453. def test_result_intersection_with_empty(self):
  4454. if self.__class__.__name__.startswith("MySQL"):
  4455. return
  4456. result1 = self.store.find(Foo, id=30)
  4457. result2 = EmptyResultSet()
  4458. result3 = result1.intersection(result2)
  4459. self.assertEquals(len(list(result3)), 0)
  4460. def test_result_intersection_count(self):
  4461. if self.__class__.__name__.startswith("MySQL"):
  4462. return
  4463. result1 = self.store.find(Foo, Foo.id.is_in((10, 20)))
  4464. result2 = self.store.find(Foo, Foo.id.is_in((10, 30)))
  4465. result3 = result1.intersection(result2)
  4466. self.assertEquals(result3.count(), 1)
  4467. def test_proxy(self):
  4468. bar = self.store.get(BarProxy, 200)
  4469. self.assertEquals(bar.foo_title, "Title 20")
  4470. def test_proxy_equals(self):
  4471. bar = self.store.find(BarProxy, BarProxy.foo_title == u"Title 20").one()
  4472. self.assertTrue(bar)
  4473. self.assertEquals(bar.id, 200)
  4474. def test_proxy_as_column(self):
  4475. result = self.store.find(BarProxy, BarProxy.id == 200)
  4476. self.assertEquals(list(result.values(BarProxy.foo_title)),
  4477. ["Title 20"])
  4478. def test_proxy_set(self):
  4479. bar = self.store.get(BarProxy, 200)
  4480. bar.foo_title = u"New Title"
  4481. foo = self.store.get(Foo, 20)
  4482. self.assertEquals(foo.title, "New Title")
  4483. def get_bar_proxy_with_string(self):
  4484. class Base(object):
  4485. __metaclass__ = PropertyPublisherMeta
  4486. class MyBarProxy(Base):
  4487. __storm_table__ = "bar"
  4488. id = Int(primary=True)
  4489. foo_id = Int()
  4490. foo = Reference("foo_id", "MyFoo.id")
  4491. foo_title = Proxy(foo, "MyFoo.title")
  4492. class MyFoo(Base):
  4493. __storm_table__ = "foo"
  4494. id = Int(primary=True)
  4495. title = Unicode()
  4496. return MyBarProxy, MyFoo
  4497. def test_proxy_with_string(self):
  4498. MyBarProxy, MyFoo = self.get_bar_proxy_with_string()
  4499. bar = self.store.get(MyBarProxy, 200)
  4500. self.assertEquals(bar.foo_title, "Title 20")
  4501. def test_proxy_with_string_variable_factory_attribute(self):
  4502. MyBarProxy, MyFoo = self.get_bar_proxy_with_string()
  4503. variable = MyBarProxy.foo_title.variable_factory(value=u"Hello")
  4504. self.assertTrue(isinstance(variable, UnicodeVariable))
  4505. def test_proxy_with_extra_table(self):
  4506. """
  4507. Proxies use a join on auto_tables. It should work even if we have
  4508. more tables in the query.
  4509. """
  4510. result = self.store.find((BarProxy, Link),
  4511. BarProxy.foo_title == u"Title 20",
  4512. BarProxy.foo_id == Link.foo_id)
  4513. results = list(result)
  4514. self.assertEquals(len(results), 2)
  4515. for bar, link in results:
  4516. self.assertEquals(bar.id, 200)
  4517. self.assertEquals(bar.foo_title, u"Title 20")
  4518. self.assertEquals(bar.foo_id, 20)
  4519. self.assertEquals(link.foo_id, 20)
  4520. def test_get_decimal_property(self):
  4521. money = self.store.get(Money, 10)
  4522. self.assertEquals(money.value, decimal.Decimal("12.3455"))
  4523. def test_set_decimal_property(self):
  4524. money = self.store.get(Money, 10)
  4525. money.value = decimal.Decimal("12.3456")
  4526. self.store.flush()
  4527. result = self.store.find(Money, value=decimal.Decimal("12.3456"))
  4528. self.assertEquals(result.one(), money)
  4529. def test_fill_missing_primary_key_with_lazy_value(self):
  4530. foo = self.store.get(Foo, 10)
  4531. foo.id = SQL("40")
  4532. self.store.flush()
  4533. self.assertEquals(foo.id, 40)
  4534. self.assertEquals(self.store.get(Foo, 10), None)
  4535. self.assertEquals(self.store.get(Foo, 40), foo)
  4536. def test_fill_missing_primary_key_with_lazy_value_on_creation(self):
  4537. foo = Foo()
  4538. foo.id = SQL("40")
  4539. self.store.add(foo)
  4540. self.store.flush()
  4541. self.assertEquals(foo.id, 40)
  4542. self.assertEquals(self.store.get(Foo, 40), foo)
  4543. def test_preset_primary_key(self):
  4544. check = []
  4545. def preset_primary_key(primary_columns, primary_variables):
  4546. check.append([(variable.is_defined(), variable.get_lazy())
  4547. for variable in primary_variables])
  4548. check.append([column.name for column in primary_columns])
  4549. primary_variables[0].set(SQL("40"))
  4550. class DatabaseWrapper(object):
  4551. """Wrapper to inject our custom preset_primary_key hook."""
  4552. def __init__(self, database):
  4553. self.database = database
  4554. def connect(self, event=None):
  4555. connection = self.database.connect(event)
  4556. connection.preset_primary_key = preset_primary_key
  4557. return connection
  4558. store = Store(DatabaseWrapper(self.database))
  4559. foo = store.add(Foo())
  4560. store.flush()
  4561. try:
  4562. self.assertEquals(check, [[(False, None)], ["id"]])
  4563. self.assertEquals(foo.id, 40)
  4564. finally:
  4565. store.close()
  4566. def test_strong_cache_used(self):
  4567. """
  4568. Objects should be referenced in the cache if not referenced
  4569. in application code.
  4570. """
  4571. foo = self.store.get(Foo, 20)
  4572. foo.tainted = True
  4573. obj_info = get_obj_info(foo)
  4574. del foo
  4575. gc.collect()
  4576. cached = self.store.find(Foo).cached()
  4577. self.assertEquals(len(cached), 1)
  4578. foo = self.store.get(Foo, 20)
  4579. self.assertEquals(cached, [foo])
  4580. self.assertTrue(hasattr(foo, "tainted"))
  4581. def test_strong_cache_cleared_on_invalidate_all(self):
  4582. cache = self.get_cache(self.store)
  4583. foo = self.store.get(Foo, 20)
  4584. self.assertEquals(cache.get_cached(), [get_obj_info(foo)])
  4585. self.store.invalidate()
  4586. self.assertEquals(cache.get_cached(), [])
  4587. def test_strong_cache_loses_object_on_invalidate(self):
  4588. cache = self.get_cache(self.store)
  4589. foo = self.store.get(Foo, 20)
  4590. self.assertEquals(cache.get_cached(), [get_obj_info(foo)])
  4591. self.store.invalidate(foo)
  4592. self.assertEquals(cache.get_cached(), [])
  4593. def test_strong_cache_loses_object_on_remove(self):
  4594. """
  4595. Make sure an object gets removed from the strong reference
  4596. cache when removed from the store.
  4597. """
  4598. cache = self.get_cache(self.store)
  4599. foo = self.store.get(Foo, 20)
  4600. self.assertEquals(cache.get_cached(), [get_obj_info(foo)])
  4601. self.store.remove(foo)
  4602. self.store.flush()
  4603. self.assertEquals(cache.get_cached(), [])
  4604. def test_strong_cache_renews_object_on_get(self):
  4605. cache = self.get_cache(self.store)
  4606. foo1 = self.store.get(Foo, 10)
  4607. foo2 = self.store.get(Foo, 20)
  4608. foo1 = self.store.get(Foo, 10)
  4609. self.assertEquals(cache.get_cached(),
  4610. [get_obj_info(foo1), get_obj_info(foo2)])
  4611. def test_strong_cache_renews_object_on_find(self):
  4612. cache = self.get_cache(self.store)
  4613. foo1 = self.store.find(Foo, id=10).one()
  4614. foo2 = self.store.find(Foo, id=20).one()
  4615. foo1 = self.store.find(Foo, id=10).one()
  4616. self.assertEquals(cache.get_cached(),
  4617. [get_obj_info(foo1), get_obj_info(foo2)])
  4618. def test_unicode(self):
  4619. class MyFoo(Foo):
  4620. pass
  4621. foo = self.store.get(Foo, 20)
  4622. myfoo = self.store.get(MyFoo, 20)
  4623. for title in [u'Cừơng', u'Đức', u'Hạnh']:
  4624. foo.title = title
  4625. self.store.commit()
  4626. try:
  4627. self.assertEquals(myfoo.title, title)
  4628. except AssertionError, e:
  4629. raise AssertionError(str(e) +
  4630. " (ensure your database was created with CREATE DATABASE"
  4631. " ... CHARACTER SET utf8)")
  4632. def test_creation_order_is_preserved_when_possible(self):
  4633. foos = [self.store.add(Foo()) for i in range(10)]
  4634. self.store.flush()
  4635. for i in range(len(foos)-1):
  4636. self.assertTrue(foos[i].id < foos[i+1].id)
  4637. def test_update_order_is_preserved_when_possible(self):
  4638. class MyFoo(Foo):
  4639. sequence = 0
  4640. def __storm_flushed__(self):
  4641. self.flush_order = MyFoo.sequence
  4642. MyFoo.sequence += 1
  4643. foos = [self.store.add(MyFoo()) for i in range(10)]
  4644. self.store.flush()
  4645. MyFoo.sequence = 0
  4646. for foo in foos:
  4647. foo.title = u"Changed Title"
  4648. self.store.flush()
  4649. for i, foo in enumerate(foos):
  4650. self.assertEquals(foo.flush_order, i)
  4651. def test_removal_order_is_preserved_when_possible(self):
  4652. class MyFoo(Foo):
  4653. sequence = 0
  4654. def __storm_flushed__(self):
  4655. self.flush_order = MyFoo.sequence
  4656. MyFoo.sequence += 1
  4657. foos = [self.store.add(MyFoo()) for i in range(10)]
  4658. self.store.flush()
  4659. MyFoo.sequence = 0
  4660. for foo in foos:
  4661. self.store.remove(foo)
  4662. self.store.flush()
  4663. for i, foo in enumerate(foos):
  4664. self.assertEquals(foo.flush_order, i)
  4665. def test_cache_poisoning(self):
  4666. """
  4667. When a object update a field value to the previous value, which is in
  4668. the cache, it correctly updates the value in the database.
  4669. Because of change detection, this has been broken in the past, see bug
  4670. #277095 in launchpad.
  4671. """
  4672. store = self.create_store()
  4673. foo2 = store.get(Foo, 10)
  4674. self.assertEquals(foo2.title, u"Title 30")
  4675. store.commit()
  4676. foo1 = self.store.get(Foo, 10)
  4677. foo1.title = u"Title 40"
  4678. self.store.commit()
  4679. foo2.title = u"Title 30"
  4680. store.commit()
  4681. self.assertEquals(foo2.title, u"Title 30")
  4682. def test_execute_sends_event(self):
  4683. """Statement execution emits the register-transaction event."""
  4684. calls = []
  4685. def register_transaction(owner):
  4686. calls.append(owner)
  4687. self.store._event.hook("register-transaction", register_transaction)
  4688. self.store.execute("SELECT 1")
  4689. self.assertEqual(len(calls), 1)
  4690. self.assertEqual(calls[0], self.store)
  4691. def test_add_sends_event(self):
  4692. """Adding an object emits the register-transaction event."""
  4693. calls = []
  4694. def register_transaction(owner):
  4695. calls.append(owner)
  4696. self.store._event.hook("register-transaction", register_transaction)
  4697. foo = Foo()
  4698. foo.title = u"Foo"
  4699. self.store.add(foo)
  4700. self.assertEqual(len(calls), 1)
  4701. self.assertEqual(calls[0], self.store)
  4702. def test_remove_sends_event(self):
  4703. """Adding an object emits the register-transaction event."""
  4704. calls = []
  4705. def register_transaction(owner):
  4706. calls.append(owner)
  4707. self.store._event.hook("register-transaction", register_transaction)
  4708. foo = self.store.get(Foo, 10)
  4709. del calls[:]
  4710. self.store.remove(foo)
  4711. self.assertEqual(len(calls), 1)
  4712. self.assertEqual(calls[0], self.store)
  4713. def test_change_invalidated_object_sends_event(self):
  4714. """Modifying an object retrieved in a previous transaction emits the
  4715. register-transaction event."""
  4716. calls = []
  4717. def register_transaction(owner):
  4718. calls.append(owner)
  4719. self.store._event.hook("register-transaction", register_transaction)
  4720. foo = self.store.get(Foo, 10)
  4721. self.store.rollback()
  4722. del calls[:]
  4723. foo.title = u"New title"
  4724. self.assertEqual(len(calls), 1)
  4725. self.assertEqual(calls[0], self.store)
  4726. def test_rowcount_remove(self):
  4727. # All supported backends support rowcount, so far.
  4728. result_to_remove = self.store.find(Foo, Foo.id <= 30)
  4729. self.assertEquals(result_to_remove.remove(), 3)
  4730. class EmptyResultSetTest(object):
  4731. def setUp(self):
  4732. self.create_database()
  4733. self.connection = self.database.connect()
  4734. self.drop_tables()
  4735. self.create_tables()
  4736. self.create_store()
  4737. # Most of the tests here exercise the same functionality using
  4738. # self.empty and self.result to ensure that EmptyResultSet and
  4739. # ResultSet behave the same way, in the same situations.
  4740. self.empty = EmptyResultSet()
  4741. self.result = self.store.find(Foo)
  4742. def tearDown(self):
  4743. self.drop_store()
  4744. self.drop_tables()
  4745. self.drop_database()
  4746. self.connection.close()
  4747. def create_database(self):
  4748. raise NotImplementedError
  4749. def create_tables(self):
  4750. raise NotImplementedError
  4751. def create_store(self):
  4752. self.store = Store(self.database)
  4753. def drop_database(self):
  4754. pass
  4755. def drop_tables(self):
  4756. for table in ["foo", "bar", "bin", "link"]:
  4757. try:
  4758. self.connection.execute("DROP TABLE %s" % table)
  4759. self.connection.commit()
  4760. except:
  4761. self.connection.rollback()
  4762. def drop_store(self):
  4763. self.store.rollback()
  4764. # Closing the store is needed because testcase objects are all
  4765. # instantiated at once, and thus connections are kept open.
  4766. self.store.close()
  4767. def test_iter(self):
  4768. self.assertEquals(list(self.result), list(self.empty))
  4769. def test_copy(self):
  4770. self.assertNotEquals(self.result.copy(), self.result)
  4771. self.assertNotEquals(self.empty.copy(), self.empty)
  4772. self.assertEquals(list(self.result.copy()), list(self.empty.copy()))
  4773. def test_config(self):
  4774. self.result.config(distinct=True, offset=1, limit=1)
  4775. self.empty.config(distinct=True, offset=1, limit=1)
  4776. self.assertEquals(list(self.result), list(self.empty))
  4777. def test_slice(self):
  4778. self.assertEquals(list(self.result[:]), [])
  4779. self.assertEquals(list(self.empty[:]), [])
  4780. def test_contains(self):
  4781. self.assertEquals(Foo() in self.empty, False)
  4782. def test_is_empty(self):
  4783. self.assertEquals(self.result.is_empty(), True)
  4784. self.assertEquals(self.empty.is_empty(), True)
  4785. def test_any(self):
  4786. self.assertEquals(self.result.any(), None)
  4787. self.assertEquals(self.empty.any(), None)
  4788. def test_first_unordered(self):
  4789. self.assertRaises(UnorderedError, self.result.first)
  4790. self.assertRaises(UnorderedError, self.empty.first)
  4791. def test_first_ordered(self):
  4792. self.result.order_by(Foo.title)
  4793. self.assertEquals(self.result.first(), None)
  4794. self.empty.order_by(Foo.title)
  4795. self.assertEquals(self.empty.first(), None)
  4796. def test_last_unordered(self):
  4797. self.assertRaises(UnorderedError, self.result.last)
  4798. self.assertRaises(UnorderedError, self.empty.last)
  4799. def test_last_ordered(self):
  4800. self.result.order_by(Foo.title)
  4801. self.assertEquals(self.result.last(), None)
  4802. self.empty.order_by(Foo.title)
  4803. self.assertEquals(self.empty.last(), None)
  4804. def test_one(self):
  4805. self.assertEquals(self.result.one(), None)
  4806. self.assertEquals(self.empty.one(), None)
  4807. def test_order_by(self):
  4808. self.assertEquals(self.result.order_by(Foo.title), self.result)
  4809. self.assertEquals(self.empty.order_by(Foo.title), self.empty)
  4810. def test_remove(self):
  4811. self.assertEquals(self.result.remove(), 0)
  4812. self.assertEquals(self.empty.remove(), 0)
  4813. def test_count(self):
  4814. self.assertEquals(self.result.count(), 0)
  4815. self.assertEquals(self.empty.count(), 0)
  4816. self.assertEquals(self.empty.count(expr="abc"), 0)
  4817. self.assertEquals(self.empty.count(distinct=True), 0)
  4818. def test_max(self):
  4819. self.assertEquals(self.result.max(Foo.id), None)
  4820. self.assertEquals(self.empty.max(Foo.id), None)
  4821. def test_min(self):
  4822. self.assertEquals(self.result.min(Foo.id), None)
  4823. self.assertEquals(self.empty.min(Foo.id), None)
  4824. def test_avg(self):
  4825. self.assertEquals(self.result.avg(Foo.id), None)
  4826. self.assertEquals(self.empty.avg(Foo.id), None)
  4827. def test_sum(self):
  4828. self.assertEquals(self.result.sum(Foo.id), None)
  4829. self.assertEquals(self.empty.sum(Foo.id), None)
  4830. def test_get_select_expr_without_columns(self):
  4831. """
  4832. A L{FeatureError} is raised if L{EmptyResultSet.get_select_expr} is
  4833. called without a list of L{Column}s.
  4834. """
  4835. self.assertRaises(FeatureError, self.result.get_select_expr)
  4836. self.assertRaises(FeatureError, self.empty.get_select_expr)
  4837. def test_get_select_expr_(self):
  4838. """
  4839. A L{FeatureError} is raised if L{EmptyResultSet.get_select_expr} is
  4840. called without a list of L{Column}s.
  4841. """
  4842. subselect = self.result.get_select_expr(Foo.id)
  4843. self.assertEqual((Foo.id,), subselect.columns)
  4844. result = self.store.find(Foo, Foo.id.is_in(subselect))
  4845. self.assertEquals(list(result), [])
  4846. subselect = self.empty.get_select_expr(Foo.id)
  4847. self.assertEqual((Foo.id,), subselect.columns)
  4848. result = self.store.find(Foo, Foo.id.is_in(subselect))
  4849. self.assertEquals(list(result), [])
  4850. def test_values_no_columns(self):
  4851. self.assertRaises(FeatureError, list, self.result.values())
  4852. self.assertRaises(FeatureError, list, self.empty.values())
  4853. def test_values(self):
  4854. self.assertEquals(list(self.result.values(Foo.title)), [])
  4855. self.assertEquals(list(self.empty.values(Foo.title)), [])
  4856. def test_set_no_args(self):
  4857. self.assertEquals(self.result.set(), None)
  4858. self.assertEquals(self.empty.set(), None)
  4859. def test_cached(self):
  4860. self.assertEquals(self.result.cached(), [])
  4861. self.assertEquals(self.empty.cached(), [])
  4862. def test_find(self):
  4863. self.assertEquals(list(self.result.find(Foo.title == u"foo")), [])
  4864. self.assertEquals(list(self.empty.find(Foo.title == u"foo")), [])
  4865. def test_union(self):
  4866. self.assertEquals(self.empty.union(self.empty), self.empty)
  4867. self.assertEquals(type(self.empty.union(self.result)),
  4868. type(self.result))
  4869. self.assertEquals(type(self.result.union(self.empty)),
  4870. type(self.result))
  4871. def test_difference(self):
  4872. self.assertEquals(self.empty.difference(self.empty), self.empty)
  4873. self.assertEquals(self.empty.difference(self.result), self.empty)
  4874. self.assertEquals(self.result.difference(self.empty), self.result)
  4875. def test_intersection(self):
  4876. self.assertEquals(self.empty.intersection(self.empty), self.empty)
  4877. self.assertEquals(self.empty.intersection(self.result), self.empty)
  4878. self.assertEquals(self.result.intersection(self.empty), self.empty)