159
162
connection.execute("INSERT INTO link VALUES (20, 200)")
160
163
connection.execute("INSERT INTO link VALUES (30, 300)")
161
164
connection.execute("INSERT INTO money VALUES (10, '12.3455')")
165
connection.execute("INSERT INTO selfref VALUES (15, 'SelfRef 15', NULL)")
166
connection.execute("INSERT INTO selfref VALUES (25, 'SelfRef 25', NULL)")
167
connection.execute("INSERT INTO selfref VALUES (35, 'SelfRef 35', 15)")
163
169
def create_store(self):
164
self.store = Store(self.database)
170
store = Store(self.database)
171
self.stores.append(store)
172
if self.store is None:
166
176
def drop_store(self):
167
self.store.rollback()
177
for store in self.stores:
169
# Closing the store is needed because testcase objects are all
170
# instantiated at once, and thus connections are kept open.
180
# Closing the store is needed because testcase objects are all
181
# instantiated at once, and thus connections are kept open.
173
184
def drop_sample_data(self):
176
187
def drop_tables(self):
177
for table in ["foo", "bar", "bin", "link", "money"]:
178
connection = self.database.connect()
188
connection = self.database.connect()
189
for table in ["foo", "bar", "bin", "link", "money", "selfref"]:
180
191
connection.execute("DROP TABLE %s" % table)
181
192
connection.commit()
196
207
result = connection.execute("SELECT * FROM foo ORDER BY id")
197
208
return list(result)
210
def get_cache(self, store):
211
# We don't offer a public API for this just yet.
200
214
def test_execute(self):
201
215
result = self.store.execute("SELECT 1")
202
216
self.assertTrue(isinstance(result, Result))
203
217
self.assertEquals(result.get_one(), (1,))
205
219
result = self.store.execute("SELECT 1", noresult=True)
206
220
self.assertEquals(result, None)
310
331
def test_obj_info_with_deleted_object_with_get(self):
311
332
# Same thing, but using get rather than find.
334
# Disable the cache, which holds strong references.
335
self.get_cache(self.store).set_size(0)
312
337
foo = self.store.get(Foo, 20)
313
338
foo.tainted = True
314
339
obj_info = get_obj_info(foo)
319
344
self.assertEquals(obj_info.get_obj(), None)
321
346
foo = self.store.get(Foo, 20)
919
951
result = self.store.using(Foo, Bar).find(Foo)
920
952
self.assertRaises(FeatureError, result.cached)
954
def test_get_does_not_validate(self):
955
def validator(object, attr, value):
956
self.fail("validator called with arguments (%r, %r, %r)" %
957
(object, attr, value))
960
__storm_table__ = "foo"
961
id = Int(primary=True)
962
title = Unicode(validator=validator)
964
foo = self.store.get(Foo, 10)
965
self.assertEqual(foo.title, "Title 30")
967
def test_get_does_not_validate_default_value(self):
968
def validator(object, attr, value):
969
self.fail("validator called with arguments (%r, %r, %r)" %
970
(object, attr, value))
973
__storm_table__ = "foo"
974
id = Int(primary=True)
975
title = Unicode(validator=validator, default=u"default value")
977
foo = self.store.get(Foo, 10)
978
self.assertEqual(foo.title, "Title 30")
980
def test_find_does_not_validate(self):
981
def validator(object, attr, value):
982
self.fail("validator called with arguments (%r, %r, %r)" %
983
(object, attr, value))
986
__storm_table__ = "foo"
987
id = Int(primary=True)
988
title = Unicode(validator=validator)
990
foo = self.store.find(Foo, Foo.id == 10).one()
991
self.assertEqual(foo.title, "Title 30")
922
993
def test_add_commit(self):
1725
1796
(30, "Title 10"),
1799
def test_wb_block_implicit_flushes(self):
1800
# Make sure calling store.flush() will fail.
1802
raise RuntimeError("Flush called")
1803
self.store.flush = flush
1805
# The following operations do not call flush.
1806
self.store.block_implicit_flushes()
1807
foo = self.store.get(Foo, 20)
1808
foo = self.store.find(Foo, Foo.id == 20).one()
1809
self.store.execute("SELECT title FROM foo WHERE id = 20")
1811
self.store.unblock_implicit_flushes()
1812
self.assertRaises(RuntimeError, self.store.get, Foo, 20)
1814
def test_wb_block_implicit_flushes_is_recursive(self):
1815
# Make sure calling store.flush() will fail.
1817
raise RuntimeError("Flush called")
1818
self.store.flush = flush
1820
self.store.block_implicit_flushes()
1821
self.store.block_implicit_flushes()
1822
self.store.unblock_implicit_flushes()
1823
# implicit flushes are still blocked, until unblock() is called again.
1824
foo = self.store.get(Foo, 20)
1825
self.store.unblock_implicit_flushes()
1826
self.assertRaises(RuntimeError, self.store.get, Foo, 20)
1728
1828
def test_reload(self):
1729
1829
foo = self.store.get(Foo, 20)
1730
1830
self.store.execute("UPDATE foo SET title='Title 40' WHERE id=20")
1949
2058
result = self.store.execute("SELECT foo_id FROM bar WHERE id=100")
1950
2059
self.assertEquals(result.get_one(), (30,))
2061
def test_set_reference_explicitly_with_wrapper(self):
2062
bar = self.store.get(Bar, 100)
2063
self.assertEquals(bar.foo.id, 10)
2064
foo = self.store.get(Foo, 30)
2065
Bar.foo.__set__(Wrapper(bar), Wrapper(foo))
2066
self.assertEquals(bar.foo.id, 30)
2067
result = self.store.execute("SELECT foo_id FROM bar WHERE id=100")
2068
self.assertEquals(result.get_one(), (30,))
1952
2070
def test_reference_assign_remote_key(self):
1953
2071
bar = self.store.get(Bar, 100)
1954
2072
self.assertEquals(bar.foo.id, 10)
2254
2388
self.store.add(bar)
2256
store = Store(self.database)
2390
store = self.create_store()
2257
2391
store.add(foo1)
2259
2393
self.assertEquals(Store.of(bar), self.store)
2260
2394
self.assertEquals(Store.of(foo1), store)
2396
def test_reference_on_removed_wont_add_back(self):
2397
bar = self.store.get(Bar, 200)
2398
foo = self.store.get(Foo, bar.foo_id)
2400
self.store.remove(bar)
2402
self.assertEquals(bar.foo, foo)
2405
self.assertEquals(Store.of(bar), None)
2406
self.assertEquals(Store.of(foo), self.store)
2262
2408
def test_reference_equals(self):
2263
2409
foo = self.store.get(Foo, 10)
2284
2430
myself=(link.foo_id, link.bar_id)).one()
2285
2431
self.assertEquals(link, myself)
2433
def test_reference_equals_with_wrapped(self):
2434
foo = self.store.get(Foo, 10)
2436
bar = self.store.find(Bar, foo=Wrapper(foo)).one()
2437
self.assertTrue(bar)
2438
self.assertEquals(bar.foo, foo)
2287
2440
def test_reference_self(self):
2441
selfref = self.store.add(SelfRef())
2443
selfref.title = u"Title 400"
2444
selfref.selfref_id = 25
2445
self.assertEquals(selfref.selfref.id, 25)
2446
self.assertEquals(selfref.selfref.title, "SelfRef 25")
2448
def get_bar_200_title(self):
2449
connection = self.store._connection
2450
result = connection.execute("SELECT title FROM bar WHERE id=200")
2451
return result.get_one()[0]
2453
def test_reference_wont_touch_store_when_key_is_none(self):
2454
bar = self.store.get(Bar, 200)
2456
bar.title = u"Don't flush this!"
2458
self.assertEquals(bar.foo, None)
2460
# Bypass the store to prevent flushing.
2461
self.assertEquals(self.get_bar_200_title(), "Title 200")
2463
def test_reference_wont_touch_store_when_key_is_unset(self):
2464
bar = self.store.get(Bar, 200)
2466
bar.title = u"Don't flush this!"
2468
self.assertEquals(bar.foo, None)
2470
# Bypass the store to prevent flushing.
2471
connection = self.store._connection
2472
result = connection.execute("SELECT title FROM bar WHERE id=200")
2473
self.assertEquals(result.get_one()[0], "Title 200")
2475
def test_reference_wont_touch_store_with_composed_key_none(self):
2288
2476
class Bar(object):
2289
2477
__storm_table__ = "bar"
2290
2478
id = Int(primary=True)
2291
2480
title = Unicode()
2292
bar_id = Int("foo_id")
2293
bar = Reference(bar_id, id)
2295
bar = self.store.add(Bar())
2297
bar.title = u"Title 400"
2299
self.assertEquals(bar.bar.id, 100)
2300
self.assertEquals(bar.bar.title, "Title 300")
2481
foo = Reference((foo_id, title), (Foo.id, Foo.title))
2483
bar = self.store.get(Bar, 200)
2487
self.assertEquals(bar.foo, None)
2489
# Bypass the store to prevent flushing.
2490
self.assertEquals(self.get_bar_200_title(), "Title 200")
2492
def test_reference_will_resolve_auto_reload(self):
2493
bar = self.store.get(Bar, 200)
2494
bar.foo_id = AutoReload
2495
self.assertTrue(bar.foo)
2302
2497
def test_back_reference(self):
2303
2498
class MyFoo(Foo):
2359
2554
"foo.title = 'Title 40'")
2360
2555
self.assertEquals(result.get_one(), ("Title 400",))
2557
def test_back_reference_assign_none_with_unseen(self):
2559
bar = Reference(Foo.id, Bar.foo_id, on_remote=True)
2560
foo = self.store.get(MyFoo, 20)
2562
self.assertEquals(foo.bar, None)
2564
def test_back_reference_assign_none_from_none(self):
2566
bar = Reference(Foo.id, Bar.foo_id, on_remote=True)
2567
self.store.execute("INSERT INTO foo (id, title)"
2568
" VALUES (40, 'Title 40')")
2570
foo = self.store.get(MyFoo, 40)
2572
self.assertEquals(foo.bar, None)
2574
def test_back_reference_on_added_unsets_original_key(self):
2576
bar = Reference(Foo.id, Bar.foo_id, on_remote=True)
2586
self.assertEquals(bar.foo_id, None)
2362
2588
def test_back_reference_on_added_no_store(self):
2363
2589
class MyFoo(Foo):
2364
2590
bar = Reference(Foo.id, Bar.foo_id, on_remote=True)
2400
2626
self.assertEquals(type(bar.foo_id), int)
2628
def test_back_reference_remove_remote(self):
2630
bar = Reference(Foo.id, Bar.foo_id, on_remote=True)
2633
bar.title = u"Title 400"
2636
foo.title = u"Title 40"
2642
self.assertEquals(foo.bar, bar)
2643
self.store.remove(bar)
2644
self.assertEquals(foo.bar, None)
2646
def test_back_reference_remove_remote_pending_add(self):
2648
bar = Reference(Foo.id, Bar.foo_id, on_remote=True)
2651
bar.title = u"Title 400"
2654
foo.title = u"Title 40"
2659
self.assertEquals(foo.bar, bar)
2660
self.store.remove(bar)
2661
self.assertEquals(foo.bar, None)
2663
def test_reference_loop_with_undefined_keys_fails(self):
2664
"""A loop of references with undefined keys raises OrderLoopError."""
2666
self.store.add(ref1)
2671
self.assertRaises(OrderLoopError, self.store.flush)
2673
def test_reference_loop_with_dirty_keys_fails(self):
2675
self.store.add(ref1)
2682
self.assertRaises(OrderLoopError, self.store.flush)
2684
def test_reference_loop_with_dirty_keys_changed_later_fails(self):
2687
self.store.add(ref1)
2688
self.store.add(ref2)
2695
self.assertRaises(OrderLoopError, self.store.flush)
2697
def test_reference_loop_with_dirty_keys_on_remote_fails(self):
2699
self.store.add(ref1)
2703
ref2.selfref_on_remote = ref1
2704
ref1.selfref_on_remote = ref2
2706
self.assertRaises(OrderLoopError, self.store.flush)
2708
def test_reference_loop_with_dirty_keys_on_remote_changed_later_fails(self):
2711
self.store.add(ref1)
2713
ref2.selfref_on_remote = ref1
2714
ref1.selfref_on_remote = ref2
2718
self.assertRaises(OrderLoopError, self.store.flush)
2720
def test_reference_loop_with_unchanged_keys_succeeds(self):
2722
self.store.add(ref1)
2725
self.store.add(ref2)
2730
# As ref1 and ref2 have been flushed to the database, so these
2731
# changes can be flushed.
2736
def test_reference_loop_with_one_unchanged_key_succeeds(self):
2738
self.store.add(ref1)
2745
# As ref1 and ref2 have been flushed to the database, so these
2746
# changes can be flushed.
2749
def test_reference_loop_with_key_changed_later_succeeds(self):
2751
self.store.add(ref1)
2760
def test_reference_loop_with_key_changed_later_on_remote_succeeds(self):
2762
self.store.add(ref1)
2766
ref2.selfref_on_remote = ref1
2771
def test_reference_loop_with_undefined_and_changed_keys_fails(self):
2773
self.store.add(ref1)
2781
self.assertRaises(OrderLoopError, self.store.flush)
2783
def test_reference_loop_with_undefined_and_changed_keys_fails2(self):
2785
self.store.add(ref1)
2793
self.assertRaises(OrderLoopError, self.store.flush)
2795
def test_reference_loop_broken_by_set(self):
2800
self.store.add(ref1)
2805
def test_reference_loop_set_only_removes_own_flush_order(self):
2808
self.store.add(ref2)
2811
# The following does not create a loop since the keys are
2812
# dirty (as shown in another test).
2816
# Now add a flush order loop.
2817
self.store.add_flush_order(ref1, ref2)
2818
self.store.add_flush_order(ref2, ref1)
2820
# Now break the reference. This should leave the flush
2821
# ordering loop we previously created in place..
2823
self.assertRaises(OrderLoopError, self.store.flush)
2402
2825
def add_reference_set_bar_400(self):
3032
3470
(200, "Title 200"),
3473
def test_indirect_reference_set_add_remove_with_wrapper(self):
3474
foo = self.store.get(FooIndRefSet, 20)
3475
bar300 = self.store.get(Bar, 300)
3476
bar200 = self.store.get(Bar, 200)
3478
foo.bars.add(Wrapper(bar300))
3479
foo.bars.remove(Wrapper(bar200))
3482
for bar in foo.bars:
3483
items.append((bar.id, bar.title))
3486
self.assertEquals(items, [
3035
3491
def test_indirect_reference_set_add_remove_with_added(self):
3036
3492
foo = FooIndRefSet()
3334
3790
self.store.reload(blob)
3335
3791
self.assertEquals(blob.bin, "\x80\x02}q\x01(U\x01aK\x01U\x01bK\x02u.")
3793
def test_undefined_variables_filled_on_find(self):
3795
Check that when data is fetched from the database on a find,
3796
it is used to fill up any undefined variables.
3798
# We do a first find to get the object_infos into the cache.
3799
foos = list(self.store.find(Foo, title=u"Title 20"))
3801
# Commit so that all foos are invalidated and variables are
3802
# set back to AutoReload.
3805
# Another find which should reuse in-memory foos.
3806
for foo in self.store.find(Foo, title=u"Title 20"):
3807
# Make sure we have all variables defined, because
3808
# values were already retrieved by the find's select.
3809
obj_info = get_obj_info(foo)
3810
for column in obj_info.variables:
3811
self.assertTrue(obj_info.variables[column].is_defined())
3813
def test_defined_variables_not_overridden_on_find(self):
3815
Check that the keep_defined=True setting in _load_object()
3816
is in place. In practice, it ensures that already defined
3817
values aren't replaced during a find, when new data comes
3818
from the database and is used whenever possible.
3820
blob = self.store.get(Blob, 20)
3821
blob.bin = "\x80\x02}q\x01U\x01aK\x01s."
3822
class PickleBlob(object):
3823
__storm_table__ = "bin"
3824
id = Int(primary=True)
3825
pickle = Pickle("bin")
3826
blob = self.store.get(PickleBlob, 20)
3828
# Now the find should not destroy our value pointer.
3829
blob = self.store.find(PickleBlob, id=20).one()
3830
self.assertTrue(value is blob.pickle)
3337
3832
def test_pickle_variable_with_deleted_object(self):
3338
3833
class PickleBlob(Blob):
3446
3940
(30, "Title 10"),
3943
def test_expr_values_flush_and_load_in_separate_steps(self):
3944
foo = self.store.get(Foo, 20)
3946
foo.title = SQL("'New title'")
3950
# It's already in the database.
3951
self.assertEquals(self.get_items(), [
3957
# But our value is now an AutoReload.
3958
lazy_value = get_obj_info(foo).variables[Foo.title].get_lazy()
3959
self.assertTrue(lazy_value is AutoReload)
3961
# Which gets resolved once touched.
3962
self.assertEquals(foo.title, u"New title")
3449
3964
def test_expr_values_flush_on_demand_with_added(self):
3452
3967
foo.title = SQL("'New title'")
3454
3969
self.store.add(foo)
3456
3971
# No commits yet.
3671
4186
self.store.autoreload(foo)
3672
4187
self.assertTrue(get_obj_info(foo) not in self.store._dirty)
4189
def test_autoreload_missing_columns_on_insertion(self):
4193
lazy_value = get_obj_info(foo).variables[Foo.title].get_lazy()
4194
self.assertEquals(lazy_value, AutoReload)
4195
self.assertEquals(foo.title, u"Default Title")
3674
4197
def test_reference_break_on_local_diverged_doesnt_autoreload(self):
3675
4198
foo = self.store.get(Foo, 10)
3676
4199
self.store.autoreload(foo)
3740
4263
self.store.invalidate(foo)
3741
4264
self.assertRaises(LostObjectError, setattr, foo, "title", u"Title 40")
3743
def test_invalidate_and_get_fills_undefined(self):
4266
def test_invalidate_and_get_returns_autoreloaded(self):
3744
4267
foo = self.store.get(Foo, 20)
3745
4268
self.store.invalidate(foo)
3748
unset_state = get_obj_info(unset_foo).variables[Foo.title].get_state()
3749
get_obj_info(foo).variables[Foo.title].set_state(unset_state)
3751
4269
foo = self.store.get(Foo, 20)
4270
self.assertEquals(get_obj_info(foo).variables[Foo.title].get_lazy(),
3752
4272
self.assertEquals(foo.title, "Title 20")
3754
4274
def test_invalidated_hook(self):
3997
4517
variable = MyBarProxy.foo_title.variable_factory(value=u"Hello")
3998
4518
self.assertTrue(isinstance(variable, UnicodeVariable))
4520
def test_proxy_with_extra_table(self):
4522
Proxies use a join on auto_tables. It should work even if we have
4523
more tables in the query.
4525
result = self.store.find((BarProxy, Link),
4526
BarProxy.foo_title == u"Title 20",
4527
BarProxy.foo_id == Link.foo_id)
4528
results = list(result)
4529
self.assertEquals(len(results), 2)
4530
for bar, link in results:
4531
self.assertEquals(bar.id, 200)
4532
self.assertEquals(bar.foo_title, u"Title 20")
4533
self.assertEquals(bar.foo_id, 20)
4534
self.assertEquals(link.foo_id, 20)
4000
4536
def test_get_decimal_property(self):
4001
4537
money = self.store.get(Money, 10)
4002
4538
self.assertEquals(money.value, decimal.Decimal("12.3455"))
4593
def test_strong_cache_used(self):
4595
Objects should be referenced in the cache if not referenced
4596
in application code.
4598
foo = self.store.get(Foo, 20)
4600
obj_info = get_obj_info(foo)
4603
cached = self.store.find(Foo).cached()
4604
self.assertEquals(len(cached), 1)
4605
foo = self.store.get(Foo, 20)
4606
self.assertEquals(cached, [foo])
4607
self.assertTrue(hasattr(foo, "tainted"))
4609
def test_strong_cache_cleared_on_invalidate_all(self):
4610
cache = self.get_cache(self.store)
4611
foo = self.store.get(Foo, 20)
4612
self.assertEquals(cache.get_cached(), [get_obj_info(foo)])
4613
self.store.invalidate()
4614
self.assertEquals(cache.get_cached(), [])
4616
def test_strong_cache_loses_object_on_invalidate(self):
4617
cache = self.get_cache(self.store)
4618
foo = self.store.get(Foo, 20)
4619
self.assertEquals(cache.get_cached(), [get_obj_info(foo)])
4620
self.store.invalidate(foo)
4621
self.assertEquals(cache.get_cached(), [])
4623
def test_strong_cache_loses_object_on_remove(self):
4625
Make sure an object gets removed from the strong reference
4626
cache when removed from the store.
4628
cache = self.get_cache(self.store)
4629
foo = self.store.get(Foo, 20)
4630
self.assertEquals(cache.get_cached(), [get_obj_info(foo)])
4631
self.store.remove(foo)
4633
self.assertEquals(cache.get_cached(), [])
4635
def test_strong_cache_renews_object_on_get(self):
4636
cache = self.get_cache(self.store)
4637
foo1 = self.store.get(Foo, 10)
4638
foo2 = self.store.get(Foo, 20)
4639
foo1 = self.store.get(Foo, 10)
4640
self.assertEquals(cache.get_cached(),
4641
[get_obj_info(foo1), get_obj_info(foo2)])
4643
def test_strong_cache_renews_object_on_find(self):
4644
cache = self.get_cache(self.store)
4645
foo1 = self.store.find(Foo, id=10).one()
4646
foo2 = self.store.find(Foo, id=20).one()
4647
foo1 = self.store.find(Foo, id=10).one()
4648
self.assertEquals(cache.get_cached(),
4649
[get_obj_info(foo1), get_obj_info(foo2)])
4651
def test_unicode(self):
4654
foo = self.store.get(Foo, 20)
4655
myfoo = self.store.get(MyFoo, 20)
4656
for title in [u'Cừơng', u'Đức', u'Hạnh']:
4660
self.assertEquals(myfoo.title, title)
4661
except AssertionError, e:
4662
raise AssertionError(str(e) +
4663
" (ensure your database was created with CREATE DATABASE"
4664
" ... CHARACTER SET utf8)")
4058
4667
class EmptyResultSetTest(object):