PageRenderTime 67ms CodeModel.GetById 26ms RepoModel.GetById 1ms app.codeStats 0ms

/gluon/tests/test_dal_nosql.py

https://github.com/eddgt/web2py
Python | 1432 lines | 1416 code | 5 blank | 11 comment | 6 complexity | 590c70f2ae532e209b4fbf335d97fd7f MD5 | raw file
Possible License(s): BSD-2-Clause, AGPL-3.0, LGPL-3.0

Large files files are truncated, but you can click here to view the full file

  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. """
  4. Unit tests for gluon.dal (NoSQL adapters)
  5. """
  6. import sys
  7. import os
  8. import glob
  9. if sys.version < "2.7":
  10. import unittest2 as unittest
  11. else:
  12. import unittest
  13. import datetime
  14. try:
  15. import cStringIO as StringIO
  16. except:
  17. from io import StringIO
  18. def fix_sys_path():
  19. """
  20. logic to have always the correct sys.path
  21. '', web2py/gluon, web2py/site-packages, web2py/ ...
  22. """
  23. def add_path_first(path):
  24. sys.path = [path] + [p for p in sys.path if (
  25. not p == path and not p == (path + '/'))]
  26. path = os.path.dirname(os.path.abspath(__file__))
  27. if not os.path.isfile(os.path.join(path,'web2py.py')):
  28. i = 0
  29. while i<10:
  30. i += 1
  31. if os.path.exists(os.path.join(path,'web2py.py')):
  32. break
  33. path = os.path.abspath(os.path.join(path, '..'))
  34. paths = [path,
  35. os.path.abspath(os.path.join(path, 'site-packages')),
  36. os.path.abspath(os.path.join(path, 'gluon')),
  37. '']
  38. [add_path_first(path) for path in paths]
  39. fix_sys_path()
  40. #for travis-ci
  41. DEFAULT_URI = os.environ.get('DB', 'sqlite:memory')
  42. print 'Testing against %s engine (%s)' % (DEFAULT_URI.partition(':')[0], DEFAULT_URI)
  43. IS_GAE = "datastore" in DEFAULT_URI
  44. IS_MONGODB = "mongodb" in DEFAULT_URI
  45. IS_IMAP = "imap" in DEFAULT_URI
  46. if IS_IMAP:
  47. from dal import IMAPAdapter
  48. from contrib import mockimaplib
  49. IMAPAdapter.driver = mockimaplib
  50. from dal import DAL, Field, Table, SQLALL
  51. def drop(table, cascade=None):
  52. # mongodb implements drop()
  53. # although it seems it does not work properly
  54. if (IS_GAE or IS_MONGODB or IS_IMAP):
  55. # GAE drop/cleanup is not implemented
  56. db = table._db
  57. db(table).delete()
  58. del db[table._tablename]
  59. del db.tables[db.tables.index(table._tablename)]
  60. db._remove_references_to(table)
  61. else:
  62. if cascade:
  63. table.drop(cascade)
  64. else:
  65. table.drop()
  66. # setup GAE dummy database
  67. if IS_GAE:
  68. from google.appengine.ext import testbed
  69. gaetestbed = testbed.Testbed()
  70. gaetestbed.activate()
  71. gaetestbed.init_datastore_v3_stub()
  72. ALLOWED_DATATYPES = [
  73. 'string',
  74. 'text',
  75. 'integer',
  76. 'boolean',
  77. 'double',
  78. 'blob',
  79. 'date',
  80. 'time',
  81. 'datetime',
  82. 'upload',
  83. 'password',
  84. 'json',
  85. ]
  86. def setUpModule():
  87. pass
  88. def tearDownModule():
  89. if os.path.isfile('sql.log'):
  90. os.unlink('sql.log')
  91. for a in glob.glob('*.table'):
  92. os.unlink(a)
  93. @unittest.skipIf(IS_GAE or IS_IMAP, 'TODO: Datastore throws "AssertionError: SyntaxError not raised"')
  94. class TestFields(unittest.TestCase):
  95. def testFieldName(self):
  96. # Check that Fields cannot start with underscores
  97. self.assertRaises(SyntaxError, Field, '_abc', 'string')
  98. # Check that Fields cannot contain punctuation other than underscores
  99. self.assertRaises(SyntaxError, Field, 'a.bc', 'string')
  100. # Check that Fields cannot be a name of a method or property of Table
  101. for x in ['drop', 'on', 'truncate']:
  102. self.assertRaises(SyntaxError, Field, x, 'string')
  103. # Check that Fields allows underscores in the body of a field name.
  104. self.assert_(Field('a_bc', 'string'),
  105. "Field isn't allowing underscores in fieldnames. It should.")
  106. def testFieldTypes(self):
  107. # Check that string, and password default length is 512
  108. for typ in ['string', 'password']:
  109. self.assert_(Field('abc', typ).length == 512,
  110. "Default length for type '%s' is not 512 or 255" % typ)
  111. # Check that upload default length is 512
  112. self.assert_(Field('abc', 'upload').length == 512,
  113. "Default length for type 'upload' is not 512")
  114. # Check that Tables passed in the type creates a reference
  115. self.assert_(Field('abc', Table(None, 'temp')).type
  116. == 'reference temp',
  117. 'Passing an Table does not result in a reference type.')
  118. def testFieldLabels(self):
  119. # Check that a label is successfully built from the supplied fieldname
  120. self.assert_(Field('abc', 'string').label == 'Abc',
  121. 'Label built is incorrect')
  122. self.assert_(Field('abc_def', 'string').label == 'Abc Def',
  123. 'Label built is incorrect')
  124. def testFieldFormatters(self): # Formatter should be called Validator
  125. # Test the default formatters
  126. for typ in ALLOWED_DATATYPES:
  127. f = Field('abc', typ)
  128. if typ not in ['date', 'time', 'datetime']:
  129. isinstance(f.formatter('test'), str)
  130. else:
  131. isinstance(f.formatter(datetime.datetime.now()), str)
  132. @unittest.skipIf(IS_GAE or IS_MONGODB, 'TODO: Datastore does accept dict objects as json field input. MongoDB assertion error Binary("x", 0) != "x"')
  133. def testRun(self):
  134. db = DAL(DEFAULT_URI, check_reserved=['all'])
  135. for ft in ['string', 'text', 'password', 'upload', 'blob']:
  136. db.define_table('tt', Field('aa', ft, default=''))
  137. self.assertEqual(isinstance(db.tt.insert(aa='x'), long), True)
  138. self.assertEqual(db().select(db.tt.aa)[0].aa, 'x')
  139. drop(db.tt)
  140. db.define_table('tt', Field('aa', 'integer', default=1))
  141. self.assertEqual(isinstance(db.tt.insert(aa=3), long), True)
  142. self.assertEqual(db().select(db.tt.aa)[0].aa, 3)
  143. drop(db.tt)
  144. db.define_table('tt', Field('aa', 'double', default=1))
  145. self.assertEqual(isinstance(db.tt.insert(aa=3.1), long), True)
  146. self.assertEqual(db().select(db.tt.aa)[0].aa, 3.1)
  147. drop(db.tt)
  148. db.define_table('tt', Field('aa', 'boolean', default=True))
  149. self.assertEqual(isinstance(db.tt.insert(aa=True), long), True)
  150. self.assertEqual(db().select(db.tt.aa)[0].aa, True)
  151. drop(db.tt)
  152. db.define_table('tt', Field('aa', 'json', default={}))
  153. self.assertEqual(isinstance(db.tt.insert(aa={}), long), True)
  154. self.assertEqual(db().select(db.tt.aa)[0].aa, {})
  155. drop(db.tt)
  156. db.define_table('tt', Field('aa', 'date',
  157. default=datetime.date.today()))
  158. t0 = datetime.date.today()
  159. self.assertEqual(isinstance(db.tt.insert(aa=t0), long), True)
  160. self.assertEqual(db().select(db.tt.aa)[0].aa, t0)
  161. drop(db.tt)
  162. db.define_table('tt', Field('aa', 'datetime',
  163. default=datetime.datetime.today()))
  164. t0 = datetime.datetime(
  165. 1971,
  166. 12,
  167. 21,
  168. 10,
  169. 30,
  170. 55,
  171. 0,
  172. )
  173. self.assertEqual(isinstance(db.tt.insert(aa=t0), long), True)
  174. self.assertEqual(db().select(db.tt.aa)[0].aa, t0)
  175. ## Row APIs
  176. row = db().select(db.tt.aa)[0]
  177. self.assertEqual(db.tt[1].aa,t0)
  178. self.assertEqual(db.tt['aa'],db.tt.aa)
  179. self.assertEqual(db.tt(1).aa,t0)
  180. self.assertTrue(db.tt(1,aa=None)==None)
  181. self.assertFalse(db.tt(1,aa=t0)==None)
  182. self.assertEqual(row.aa,t0)
  183. self.assertEqual(row['aa'],t0)
  184. self.assertEqual(row['tt.aa'],t0)
  185. self.assertEqual(row('tt.aa'),t0)
  186. ## Lazy and Virtual fields
  187. db.tt.b = Field.Virtual(lambda row: row.tt.aa)
  188. db.tt.c = Field.Lazy(lambda row: row.tt.aa)
  189. row = db().select(db.tt.aa)[0]
  190. self.assertEqual(row.b,t0)
  191. self.assertEqual(row.c(),t0)
  192. drop(db.tt)
  193. db.define_table('tt', Field('aa', 'time', default='11:30'))
  194. t0 = datetime.time(10, 30, 55)
  195. self.assertEqual(isinstance(db.tt.insert(aa=t0), long), True)
  196. self.assertEqual(db().select(db.tt.aa)[0].aa, t0)
  197. drop(db.tt)
  198. @unittest.skipIf(IS_GAE or IS_IMAP, 'TODO: Datastore throws "AssertionError: SyntaxError not raised"')
  199. class TestTables(unittest.TestCase):
  200. def testTableNames(self):
  201. # Check that Tables cannot start with underscores
  202. self.assertRaises(SyntaxError, Table, None, '_abc')
  203. # Check that Tables cannot contain punctuation other than underscores
  204. self.assertRaises(SyntaxError, Table, None, 'a.bc')
  205. # Check that Tables cannot be a name of a method or property of DAL
  206. for x in ['define_table', 'tables', 'as_dict']:
  207. self.assertRaises(SyntaxError, Table, None, x)
  208. # Check that Table allows underscores in the body of a field name.
  209. self.assert_(Table(None, 'a_bc'),
  210. "Table isn't allowing underscores in tablename. It should.")
  211. @unittest.skipIf(IS_IMAP, "Skip IMAP")
  212. class TestAll(unittest.TestCase):
  213. def setUp(self):
  214. self.pt = Table(None,'PseudoTable',Field('name'),Field('birthdate'))
  215. def testSQLALL(self):
  216. ans = 'PseudoTable.id, PseudoTable.name, PseudoTable.birthdate'
  217. self.assertEqual(str(SQLALL(self.pt)), ans)
  218. @unittest.skipIf(IS_IMAP, "Skip IMAP")
  219. class TestTable(unittest.TestCase):
  220. def testTableCreation(self):
  221. # Check for error when not passing type other than Field or Table
  222. self.assertRaises(SyntaxError, Table, None, 'test', None)
  223. persons = Table(None, 'persons',
  224. Field('firstname','string'),
  225. Field('lastname', 'string'))
  226. # Does it have the correct fields?
  227. self.assert_(set(persons.fields).issuperset(set(['firstname',
  228. 'lastname'])))
  229. # ALL is set correctly
  230. self.assert_('persons.firstname, persons.lastname'
  231. in str(persons.ALL))
  232. @unittest.skipIf(IS_GAE or IS_MONGODB, "No table alias for this backend")
  233. def testTableAlias(self):
  234. db = DAL(DEFAULT_URI, check_reserved=['all'])
  235. persons = Table(db, 'persons', Field('firstname',
  236. 'string'), Field('lastname', 'string'))
  237. aliens = persons.with_alias('aliens')
  238. # Are the different table instances with the same fields
  239. self.assert_(persons is not aliens)
  240. self.assert_(set(persons.fields) == set(aliens.fields))
  241. def testTableInheritance(self):
  242. persons = Table(None, 'persons', Field('firstname',
  243. 'string'), Field('lastname', 'string'))
  244. customers = Table(None, 'customers',
  245. Field('items_purchased', 'integer'),
  246. persons)
  247. self.assert_(set(customers.fields).issuperset(set(
  248. ['items_purchased', 'firstname', 'lastname'])))
  249. class TestInsert(unittest.TestCase):
  250. def testRun(self):
  251. if IS_IMAP:
  252. imap = DAL(DEFAULT_URI)
  253. imap.define_tables()
  254. self.assertEqual(imap.Draft.insert(to="nurse@example.com",
  255. subject="Nurse!",
  256. sender="gumby@example.com",
  257. content="Nurse!\r\nNurse!"), 2)
  258. self.assertEqual(imap.Draft[2].subject, "Nurse!")
  259. self.assertEqual(imap.Draft[2].sender, "gumby@example.com")
  260. self.assertEqual(isinstance(imap.Draft[2].uid, long), True)
  261. self.assertEqual(imap.Draft[2].content[0]["text"], "Nurse!\r\nNurse!")
  262. else:
  263. db = DAL(DEFAULT_URI, check_reserved=['all'])
  264. db.define_table('tt', Field('aa'))
  265. self.assertEqual(isinstance(db.tt.insert(aa='1'), long), True)
  266. self.assertEqual(isinstance(db.tt.insert(aa='1'), long), True)
  267. self.assertEqual(isinstance(db.tt.insert(aa='1'), long), True)
  268. self.assertEqual(db(db.tt.aa == '1').count(), 3)
  269. self.assertEqual(db(db.tt.aa == '2').isempty(), True)
  270. self.assertEqual(db(db.tt.aa == '1').update(aa='2'), 3)
  271. self.assertEqual(db(db.tt.aa == '2').count(), 3)
  272. self.assertEqual(db(db.tt.aa == '2').isempty(), False)
  273. self.assertEqual(db(db.tt.aa == '2').delete(), 3)
  274. self.assertEqual(db(db.tt.aa == '2').isempty(), True)
  275. drop(db.tt)
  276. @unittest.skipIf(IS_GAE or IS_MONGODB or IS_IMAP, 'TODO: Datastore throws "SyntaxError: Not supported (query using or)". MongoDB assertionerror 5L != 3')
  277. class TestSelect(unittest.TestCase):
  278. def testRun(self):
  279. db = DAL(DEFAULT_URI, check_reserved=['all'])
  280. db.define_table('tt', Field('aa'))
  281. self.assertEqual(isinstance(db.tt.insert(aa='1'), long), True)
  282. self.assertEqual(isinstance(db.tt.insert(aa='2'), long), True)
  283. self.assertEqual(isinstance(db.tt.insert(aa='3'), long), True)
  284. self.assertEqual(db(db.tt.id > 0).count(), 3)
  285. self.assertEqual(db(db.tt.id > 0).select(orderby=~db.tt.aa
  286. | db.tt.id)[0].aa, '3')
  287. self.assertEqual(len(db(db.tt.id > 0).select(limitby=(1, 2))), 1)
  288. self.assertEqual(db(db.tt.id > 0).select(limitby=(1, 2))[0].aa,
  289. '2')
  290. self.assertEqual(len(db().select(db.tt.ALL)), 3)
  291. self.assertEqual(db(db.tt.aa == None).count(), 0)
  292. self.assertEqual(db(db.tt.aa != None).count(), 3)
  293. self.assertEqual(db(db.tt.aa > '1').count(), 2)
  294. self.assertEqual(db(db.tt.aa >= '1').count(), 3)
  295. self.assertEqual(db(db.tt.aa == '1').count(), 1)
  296. self.assertEqual(db(db.tt.aa != '1').count(), 2)
  297. self.assertEqual(db(db.tt.aa < '3').count(), 2)
  298. self.assertEqual(db(db.tt.aa <= '3').count(), 3)
  299. self.assertEqual(db(db.tt.aa > '1')(db.tt.aa < '3').count(), 1)
  300. self.assertEqual(db((db.tt.aa > '1') & (db.tt.aa < '3')).count(), 1)
  301. self.assertEqual(db((db.tt.aa > '1') | (db.tt.aa < '3')).count(), 3)
  302. self.assertEqual(db((db.tt.aa > '1') & ~(db.tt.aa > '2')).count(), 1)
  303. self.assertEqual(db(~(db.tt.aa > '1') & (db.tt.aa > '2')).count(), 0)
  304. drop(db.tt)
  305. @unittest.skipIf(IS_IMAP, "TODO: IMAP test")
  306. class TestAddMethod(unittest.TestCase):
  307. def testRun(self):
  308. db = DAL(DEFAULT_URI, check_reserved=['all'])
  309. db.define_table('tt', Field('aa'))
  310. @db.tt.add_method.all
  311. def select_all(table,orderby=None):
  312. return table._db(table).select(orderby=orderby)
  313. self.assertEqual(isinstance(db.tt.insert(aa='1'), long), True)
  314. self.assertEqual(isinstance(db.tt.insert(aa='2'), long), True)
  315. self.assertEqual(isinstance(db.tt.insert(aa='3'), long), True)
  316. self.assertEqual(len(db.tt.all()), 3)
  317. drop(db.tt)
  318. @unittest.skipIf(IS_IMAP, "TODO: IMAP test")
  319. class TestBelongs(unittest.TestCase):
  320. def testRun(self):
  321. db = DAL(DEFAULT_URI, check_reserved=['all'])
  322. db.define_table('tt', Field('aa'))
  323. self.assertEqual(isinstance(db.tt.insert(aa='1'), long), True)
  324. self.assertEqual(isinstance(db.tt.insert(aa='2'), long), True)
  325. self.assertEqual(isinstance(db.tt.insert(aa='3'), long), True)
  326. self.assertEqual(db(db.tt.aa.belongs(('1', '3'))).count(),
  327. 2)
  328. if not (IS_GAE or IS_MONGODB):
  329. self.assertEqual(db(db.tt.aa.belongs(db(db.tt.id > 2)._select(db.tt.aa))).count(), 1)
  330. self.assertEqual(db(db.tt.aa.belongs(db(db.tt.aa.belongs(('1',
  331. '3')))._select(db.tt.aa))).count(), 2)
  332. self.assertEqual(db(db.tt.aa.belongs(db(db.tt.aa.belongs(db
  333. (db.tt.aa.belongs(('1', '3')))._select(db.tt.aa)))._select(
  334. db.tt.aa))).count(),
  335. 2)
  336. else:
  337. print "Datastore/Mongodb belongs does not accept queries (skipping)"
  338. drop(db.tt)
  339. @unittest.skipIf(IS_GAE or IS_IMAP, "Contains not supported on GAE Datastore. TODO: IMAP tests")
  340. class TestContains(unittest.TestCase):
  341. @unittest.skipIf(IS_MONGODB, "TODO: MongoDB Contains error")
  342. def testRun(self):
  343. db = DAL(DEFAULT_URI, check_reserved=['all'])
  344. db.define_table('tt', Field('aa', 'list:string'), Field('bb','string'))
  345. self.assertEqual(isinstance(db.tt.insert(aa=['aaa','bbb'],bb='aaa'), long), True)
  346. self.assertEqual(isinstance(db.tt.insert(aa=['bbb','ddd'],bb='abb'), long), True)
  347. self.assertEqual(isinstance(db.tt.insert(aa=['eee','aaa'],bb='acc'), long), True)
  348. self.assertEqual(db(db.tt.aa.contains('aaa')).count(), 2)
  349. self.assertEqual(db(db.tt.aa.contains('bbb')).count(), 2)
  350. self.assertEqual(db(db.tt.aa.contains('aa')).count(), 0)
  351. self.assertEqual(db(db.tt.bb.contains('a')).count(), 3)
  352. self.assertEqual(db(db.tt.bb.contains('b')).count(), 1)
  353. self.assertEqual(db(db.tt.bb.contains('d')).count(), 0)
  354. self.assertEqual(db(db.tt.aa.contains(db.tt.bb)).count(), 1)
  355. drop(db.tt)
  356. @unittest.skipIf(IS_GAE or IS_MONGODB or IS_IMAP, "Like not supported on GAE Datastore. TODO: IMAP test")
  357. class TestLike(unittest.TestCase):
  358. def testRun(self):
  359. db = DAL(DEFAULT_URI, check_reserved=['all'])
  360. db.define_table('tt', Field('aa'))
  361. self.assertEqual(isinstance(db.tt.insert(aa='abc'), long), True)
  362. self.assertEqual(db(db.tt.aa.like('a%')).count(), 1)
  363. self.assertEqual(db(db.tt.aa.like('%b%')).count(), 1)
  364. self.assertEqual(db(db.tt.aa.like('%c')).count(), 1)
  365. self.assertEqual(db(db.tt.aa.like('%d%')).count(), 0)
  366. self.assertEqual(db(db.tt.aa.lower().like('A%')).count(), 1)
  367. self.assertEqual(db(db.tt.aa.lower().like('%B%')).count(),
  368. 1)
  369. self.assertEqual(db(db.tt.aa.lower().like('%C')).count(), 1)
  370. self.assertEqual(db(db.tt.aa.upper().like('A%')).count(), 1)
  371. self.assertEqual(db(db.tt.aa.upper().like('%B%')).count(),
  372. 1)
  373. self.assertEqual(db(db.tt.aa.upper().like('%C')).count(), 1)
  374. drop(db.tt)
  375. db.define_table('tt', Field('aa', 'integer'))
  376. self.assertEqual(isinstance(db.tt.insert(aa=1111111111), long), True)
  377. self.assertEqual(db(db.tt.aa.like('1%')).count(), 1)
  378. self.assertEqual(db(db.tt.aa.like('2%')).count(), 0)
  379. drop(db.tt)
  380. @unittest.skipIf(IS_IMAP, "TODO: IMAP test")
  381. class TestDatetime(unittest.TestCase):
  382. def testRun(self):
  383. db = DAL(DEFAULT_URI, check_reserved=['all'])
  384. db.define_table('tt', Field('aa', 'datetime'))
  385. self.assertEqual(isinstance(db.tt.insert(aa=datetime.datetime(1971, 12, 21,
  386. 11, 30)), long), True)
  387. self.assertEqual(isinstance(db.tt.insert(aa=datetime.datetime(1971, 11, 21,
  388. 10, 30)), long), True)
  389. self.assertEqual(isinstance(db.tt.insert(aa=datetime.datetime(1970, 12, 21,
  390. 9, 30)), long), True)
  391. self.assertEqual(db(db.tt.aa == datetime.datetime(1971, 12,
  392. 21, 11, 30)).count(), 1)
  393. self.assertEqual(db(db.tt.aa >= datetime.datetime(1971, 1, 1)).count(), 2)
  394. drop(db.tt)
  395. @unittest.skipIf(IS_GAE or IS_MONGODB or IS_IMAP, "Expressions are not supported")
  396. class TestExpressions(unittest.TestCase):
  397. def testRun(self):
  398. db = DAL(DEFAULT_URI, check_reserved=['all'])
  399. db.define_table('tt', Field('aa', 'integer'))
  400. self.assertEqual(isinstance(db.tt.insert(aa=1), long), True)
  401. self.assertEqual(isinstance(db.tt.insert(aa=2), long), True)
  402. self.assertEqual(isinstance(db.tt.insert(aa=3), long), True)
  403. self.assertEqual(db(db.tt.aa == 3).update(aa=db.tt.aa + 1), 1)
  404. self.assertEqual(db(db.tt.aa == 4).count(), 1)
  405. self.assertEqual(db(db.tt.aa == -2).count(), 0)
  406. sum = (db.tt.aa + 1).sum()
  407. self.assertEqual(db(db.tt.aa == 2).select(sum).first()[sum], 3)
  408. self.assertEqual(db(db.tt.aa == -2).select(sum).first()[sum], None)
  409. drop(db.tt)
  410. @unittest.skip("JOIN queries are not supported")
  411. class TestJoin(unittest.TestCase):
  412. def testRun(self):
  413. db = DAL(DEFAULT_URI, check_reserved=['all'])
  414. db.define_table('t1', Field('aa'))
  415. db.define_table('t2', Field('aa'), Field('b', db.t1))
  416. i1 = db.t1.insert(aa='1')
  417. i2 = db.t1.insert(aa='2')
  418. i3 = db.t1.insert(aa='3')
  419. db.t2.insert(aa='4', b=i1)
  420. db.t2.insert(aa='5', b=i2)
  421. db.t2.insert(aa='6', b=i2)
  422. self.assertEqual(len(db(db.t1.id
  423. == db.t2.b).select(orderby=db.t1.aa
  424. | db.t2.aa)), 3)
  425. self.assertEqual(db(db.t1.id == db.t2.b).select(orderby=db.t1.aa
  426. | db.t2.aa)[2].t1.aa, '2')
  427. self.assertEqual(db(db.t1.id == db.t2.b).select(orderby=db.t1.aa
  428. | db.t2.aa)[2].t2.aa, '6')
  429. self.assertEqual(len(db().select(db.t1.ALL, db.t2.ALL,
  430. left=db.t2.on(db.t1.id == db.t2.b),
  431. orderby=db.t1.aa | db.t2.aa)), 4)
  432. self.assertEqual(db().select(db.t1.ALL, db.t2.ALL,
  433. left=db.t2.on(db.t1.id == db.t2.b),
  434. orderby=db.t1.aa | db.t2.aa)[2].t1.aa, '2')
  435. self.assertEqual(db().select(db.t1.ALL, db.t2.ALL,
  436. left=db.t2.on(db.t1.id == db.t2.b),
  437. orderby=db.t1.aa | db.t2.aa)[2].t2.aa, '6')
  438. self.assertEqual(db().select(db.t1.ALL, db.t2.ALL,
  439. left=db.t2.on(db.t1.id == db.t2.b),
  440. orderby=db.t1.aa | db.t2.aa)[3].t1.aa, '3')
  441. self.assertEqual(db().select(db.t1.ALL, db.t2.ALL,
  442. left=db.t2.on(db.t1.id == db.t2.b),
  443. orderby=db.t1.aa | db.t2.aa)[3].t2.aa, None)
  444. self.assertEqual(len(db().select(db.t1.aa, db.t2.id.count(),
  445. left=db.t2.on(db.t1.id == db.t2.b),
  446. orderby=db.t1.aa, groupby=db.t1.aa)),
  447. 3)
  448. self.assertEqual(db().select(db.t1.aa, db.t2.id.count(),
  449. left=db.t2.on(db.t1.id == db.t2.b),
  450. orderby=db.t1.aa,
  451. groupby=db.t1.aa)[0]._extra[db.t2.id.count()],
  452. 1)
  453. self.assertEqual(db().select(db.t1.aa, db.t2.id.count(),
  454. left=db.t2.on(db.t1.id == db.t2.b),
  455. orderby=db.t1.aa,
  456. groupby=db.t1.aa)[1]._extra[db.t2.id.count()],
  457. 2)
  458. self.assertEqual(db().select(db.t1.aa, db.t2.id.count(),
  459. left=db.t2.on(db.t1.id == db.t2.b),
  460. orderby=db.t1.aa,
  461. groupby=db.t1.aa)[2]._extra[db.t2.id.count()],
  462. 0)
  463. drop(db.t2)
  464. drop(db.t1)
  465. db.define_table('person',Field('name'))
  466. id = db.person.insert(name="max")
  467. self.assertEqual(id.name,'max')
  468. db.define_table('dog',Field('name'),Field('ownerperson','reference person'))
  469. db.dog.insert(name='skipper',ownerperson=1)
  470. row = db(db.person.id==db.dog.ownerperson).select().first()
  471. self.assertEqual(row[db.person.name],'max')
  472. self.assertEqual(row['person.name'],'max')
  473. drop(db.dog)
  474. self.assertEqual(len(db.person._referenced_by),0)
  475. drop(db.person)
  476. class TestMinMaxSumAvg(unittest.TestCase):
  477. @unittest.skipIf(IS_GAE or IS_MONGODB or IS_IMAP, 'TODO: Datastore throws "AttributeError: Row object has no attribute _extra"')
  478. def testRun(self):
  479. db = DAL(DEFAULT_URI, check_reserved=['all'])
  480. db.define_table('tt', Field('aa', 'integer'))
  481. self.assertEqual(isinstance(db.tt.insert(aa=1), long), True)
  482. self.assertEqual(isinstance(db.tt.insert(aa=2), long), True)
  483. self.assertEqual(isinstance(db.tt.insert(aa=3), long), True)
  484. s = db.tt.aa.min()
  485. self.assertEqual(db(db.tt.id > 0).select(s)[0]._extra[s], 1)
  486. self.assertEqual(db(db.tt.id > 0).select(s).first()[s], 1)
  487. self.assertEqual(db().select(s).first()[s], 1)
  488. s = db.tt.aa.max()
  489. self.assertEqual(db().select(s).first()[s], 3)
  490. s = db.tt.aa.sum()
  491. self.assertEqual(db().select(s).first()[s], 6)
  492. s = db.tt.aa.count()
  493. self.assertEqual(db().select(s).first()[s], 3)
  494. s = db.tt.aa.avg()
  495. self.assertEqual(db().select(s).first()[s], 2)
  496. drop(db.tt)
  497. @unittest.skipIf(IS_IMAP, "TODO: IMAP test")
  498. class TestCache(unittest.TestCase):
  499. def testRun(self):
  500. from cache import CacheInRam
  501. cache = CacheInRam()
  502. db = DAL(DEFAULT_URI, check_reserved=['all'])
  503. db.define_table('tt', Field('aa'))
  504. db.tt.insert(aa='1')
  505. r0 = db().select(db.tt.ALL)
  506. r1 = db().select(db.tt.ALL, cache=(cache, 1000))
  507. self.assertEqual(len(r0),len(r1))
  508. r2 = db().select(db.tt.ALL, cache=(cache, 1000))
  509. self.assertEqual(len(r0),len(r2))
  510. r3 = db().select(db.tt.ALL, cache=(cache, 1000), cacheable=True)
  511. self.assertEqual(len(r0),len(r3))
  512. r4 = db().select(db.tt.ALL, cache=(cache, 1000), cacheable=True)
  513. self.assertEqual(len(r0),len(r4))
  514. drop(db.tt)
  515. @unittest.skipIf(IS_IMAP, "Skip IMAP")
  516. class TestMigrations(unittest.TestCase):
  517. def testRun(self):
  518. db = DAL(DEFAULT_URI, check_reserved=['all'])
  519. db.define_table('tt', Field('aa'), migrate='.storage.table')
  520. db.commit()
  521. db.close()
  522. db = DAL(DEFAULT_URI, check_reserved=['all'])
  523. db.define_table('tt', Field('aa'), Field('b'),
  524. migrate='.storage.table')
  525. db.commit()
  526. db.close()
  527. db = DAL(DEFAULT_URI, check_reserved=['all'])
  528. db.define_table('tt', Field('aa'), Field('b', 'text'),
  529. migrate='.storage.table')
  530. db.commit()
  531. db.close()
  532. db = DAL(DEFAULT_URI, check_reserved=['all'])
  533. db.define_table('tt', Field('aa'), migrate='.storage.table')
  534. drop(db.tt)
  535. db.commit()
  536. db.close()
  537. def tearDown(self):
  538. if os.path.exists('.storage.db'):
  539. os.unlink('.storage.db')
  540. if os.path.exists('.storage.table'):
  541. os.unlink('.storage.table')
  542. class TestReference(unittest.TestCase):
  543. @unittest.skipIf(IS_MONGODB or IS_IMAP, "TODO: MongoDB assertion error (long object has no attribute id)")
  544. def testRun(self):
  545. db = DAL(DEFAULT_URI, check_reserved=['all'])
  546. if DEFAULT_URI.startswith('mssql'):
  547. #multiple cascade gotcha
  548. for key in ['reference','reference FK']:
  549. db._adapter.types[key]=db._adapter.types[key].replace(
  550. '%(on_delete_action)s','NO ACTION')
  551. db.define_table('tt', Field('name'), Field('aa','reference tt'))
  552. db.commit()
  553. x = db.tt.insert(name='max')
  554. assert isinstance(x.id, long) == True
  555. assert isinstance(x['id'], long) == True
  556. x.aa = x
  557. assert isinstance(x.aa, long) == True
  558. x.update_record()
  559. y = db.tt[x.id]
  560. assert y.aa == x.aa
  561. assert y.aa.aa.aa.aa.aa.aa.name == 'max'
  562. z=db.tt.insert(name='xxx', aa = y)
  563. assert z.aa == y.id
  564. drop(db.tt)
  565. db.commit()
  566. @unittest.skipIf(IS_IMAP, "Skip IMAP")
  567. class TestClientLevelOps(unittest.TestCase):
  568. def testRun(self):
  569. db = DAL(DEFAULT_URI, check_reserved=['all'])
  570. db.define_table('tt', Field('aa'))
  571. db.commit()
  572. db.tt.insert(aa="test")
  573. rows1 = db(db.tt.aa=='test').select()
  574. rows2 = db(db.tt.aa=='test').select()
  575. rows3 = rows1 & rows2
  576. assert len(rows3) == 2
  577. rows4 = rows1 | rows2
  578. assert len(rows4) == 1
  579. rows5 = rows1.find(lambda row: row.aa=="test")
  580. assert len(rows5) == 1
  581. rows6 = rows2.exclude(lambda row: row.aa=="test")
  582. assert len(rows6) == 1
  583. rows7 = rows5.sort(lambda row: row.aa)
  584. assert len(rows7) == 1
  585. drop(db.tt)
  586. db.commit()
  587. @unittest.skipIf(IS_IMAP, "TODO: IMAP test")
  588. class TestVirtualFields(unittest.TestCase):
  589. def testRun(self):
  590. db = DAL(DEFAULT_URI, check_reserved=['all'])
  591. db.define_table('tt', Field('aa'))
  592. db.commit()
  593. db.tt.insert(aa="test")
  594. class Compute:
  595. def a_upper(row): return row.tt.aa.upper()
  596. db.tt.virtualfields.append(Compute())
  597. assert db(db.tt.id>0).select().first().a_upper == 'TEST'
  598. drop(db.tt)
  599. db.commit()
  600. @unittest.skipIf(IS_IMAP, "TODO: IMAP test")
  601. class TestComputedFields(unittest.TestCase):
  602. def testRun(self):
  603. db = DAL(DEFAULT_URI, check_reserved=['all'])
  604. db.define_table('tt',
  605. Field('aa'),
  606. Field('bb',default='x'),
  607. Field('cc',compute=lambda r: r.aa+r.bb))
  608. db.commit()
  609. id = db.tt.insert(aa="z")
  610. self.assertEqual(db.tt[id].cc,'zx')
  611. drop(db.tt)
  612. db.commit()
  613. # test checking that a compute field can refer to earlier-defined computed fields
  614. db.define_table('tt',
  615. Field('aa'),
  616. Field('bb',default='x'),
  617. Field('cc',compute=lambda r: r.aa+r.bb),
  618. Field('dd',compute=lambda r: r.bb + r.cc))
  619. db.commit()
  620. id = db.tt.insert(aa="z")
  621. self.assertEqual(db.tt[id].dd,'xzx')
  622. drop(db.tt)
  623. db.commit()
  624. @unittest.skipIf(IS_IMAP, "TODO: IMAP test")
  625. class TestCommonFilters(unittest.TestCase):
  626. @unittest.skipIf(IS_MONGODB, "TODO: MongoDB Assertion error")
  627. def testRun(self):
  628. db = DAL(DEFAULT_URI, check_reserved=['all'])
  629. db.define_table('t1', Field('aa'))
  630. # db.define_table('t2', Field('aa'), Field('b', db.t1))
  631. i1 = db.t1.insert(aa='1')
  632. i2 = db.t1.insert(aa='2')
  633. i3 = db.t1.insert(aa='3')
  634. # db.t2.insert(aa='4', b=i1)
  635. # db.t2.insert(aa='5', b=i2)
  636. # db.t2.insert(aa='6', b=i2)
  637. db.t1._common_filter = lambda q: db.t1.aa>'1'
  638. self.assertEqual(db(db.t1).count(),2)
  639. # self.assertEqual(db(db.t1).count(),2)
  640. # q = db.t2.b==db.t1.id
  641. # q = db.t1.aa != None
  642. # self.assertEqual(db(q).count(),2)
  643. # self.assertEqual(db(q).count(),2)
  644. # self.assertEqual(len(db(db.t1).select(left=db.t2.on(q))),3)
  645. # db.t2._common_filter = lambda q: db.t2.aa<6
  646. # self.assertEqual(db(q).count(),1)
  647. # self.assertEqual(db(q).count(),1)
  648. # self.assertEqual(len(db(db.t1).select(left=db.t2.on(q))),2)
  649. # drop(db.t2)
  650. drop(db.t1)
  651. @unittest.skipIf(IS_IMAP, "Skip IMAP test")
  652. class TestImportExportFields(unittest.TestCase):
  653. def testRun(self):
  654. db = DAL(DEFAULT_URI, check_reserved=['all'])
  655. db.define_table('person', Field('name'))
  656. db.define_table('pet',Field('friend',db.person),Field('name'))
  657. for n in range(2):
  658. db(db.pet).delete()
  659. db(db.person).delete()
  660. for k in range(10):
  661. id = db.person.insert(name=str(k))
  662. db.pet.insert(friend=id,name=str(k))
  663. db.commit()
  664. stream = StringIO.StringIO()
  665. db.export_to_csv_file(stream)
  666. db(db.pet).delete()
  667. db(db.person).delete()
  668. stream = StringIO.StringIO(stream.getvalue())
  669. db.import_from_csv_file(stream)
  670. assert db(db.person).count()==10
  671. assert db(db.pet.name).count()==10
  672. drop(db.pet)
  673. drop(db.person)
  674. db.commit()
  675. @unittest.skipIf(IS_IMAP, "Skip IMAP test")
  676. class TestImportExportUuidFields(unittest.TestCase):
  677. def testRun(self):
  678. db = DAL(DEFAULT_URI, check_reserved=['all'])
  679. db.define_table('person', Field('name'),Field('uuid'))
  680. db.define_table('pet',Field('friend',db.person),Field('name'))
  681. for n in range(2):
  682. db(db.pet).delete()
  683. db(db.person).delete()
  684. for k in range(10):
  685. id = db.person.insert(name=str(k),uuid=str(k))
  686. db.pet.insert(friend=id,name=str(k))
  687. db.commit()
  688. stream = StringIO.StringIO()
  689. db.export_to_csv_file(stream)
  690. db(db.person).delete()
  691. db(db.pet).delete()
  692. stream = StringIO.StringIO(stream.getvalue())
  693. db.import_from_csv_file(stream)
  694. assert db(db.person).count()==10
  695. assert db(db.pet).count()==10
  696. drop(db.pet)
  697. drop(db.person)
  698. db.commit()
  699. @unittest.skipIf(IS_IMAP, "Skip IMAP test")
  700. class TestDALDictImportExport(unittest.TestCase):
  701. def testRun(self):
  702. db = DAL(DEFAULT_URI, check_reserved=['all'])
  703. db.define_table('person', Field('name', default="Michael"),Field('uuid'))
  704. db.define_table('pet',Field('friend',db.person),Field('name'))
  705. dbdict = db.as_dict(flat=True, sanitize=False)
  706. assert isinstance(dbdict, dict)
  707. uri = dbdict["uri"]
  708. assert isinstance(uri, basestring) and uri
  709. assert len(dbdict["tables"]) == 2
  710. assert len(dbdict["tables"][0]["fields"]) == 3
  711. assert dbdict["tables"][0]["fields"][1]["type"] == db.person.name.type
  712. assert dbdict["tables"][0]["fields"][1]["default"] == db.person.name.default
  713. db2 = DAL(**dbdict)
  714. assert len(db.tables) == len(db2.tables)
  715. assert hasattr(db2, "pet") and isinstance(db2.pet, Table)
  716. assert hasattr(db2.pet, "friend") and isinstance(db2.pet.friend, Field)
  717. drop(db.pet)
  718. db.commit()
  719. db2.commit()
  720. have_serializers = True
  721. try:
  722. import serializers
  723. dbjson = db.as_json(sanitize=False)
  724. assert isinstance(dbjson, basestring) and len(dbjson) > 0
  725. unicode_keys = True
  726. if sys.version < "2.6.5":
  727. unicode_keys = False
  728. db3 = DAL(**serializers.loads_json(dbjson,
  729. unicode_keys=unicode_keys))
  730. assert hasattr(db3, "person") and hasattr(db3.person, "uuid") and\
  731. db3.person.uuid.type == db.person.uuid.type
  732. drop(db3.person)
  733. db3.commit()
  734. except ImportError:
  735. pass
  736. mpfc = "Monty Python's Flying Circus"
  737. dbdict4 = {"uri": DEFAULT_URI,
  738. "tables":[{"tablename": "tvshow",
  739. "fields": [{"fieldname": "name",
  740. "default":mpfc},
  741. {"fieldname": "rating",
  742. "type":"double"}]},
  743. {"tablename": "staff",
  744. "fields": [{"fieldname": "name",
  745. "default":"Michael"},
  746. {"fieldname": "food",
  747. "default":"Spam"},
  748. {"fieldname": "tvshow",
  749. "type": "reference tvshow"}]}]}
  750. db4 = DAL(**dbdict4)
  751. assert "staff" in db4.tables
  752. assert "name" in db4.staff
  753. assert db4.tvshow.rating.type == "double"
  754. assert (isinstance(db4.tvshow.insert(), long), isinstance(db4.tvshow.insert(name="Loriot"), long),
  755. isinstance(db4.tvshow.insert(name="Il Mattatore"), long)) == (True, True, True)
  756. assert isinstance(db4(db4.tvshow).select().first().id, long) == True
  757. assert db4(db4.tvshow).select().first().name == mpfc
  758. drop(db4.staff)
  759. drop(db4.tvshow)
  760. db4.commit()
  761. dbdict5 = {"uri": DEFAULT_URI}
  762. db5 = DAL(**dbdict5)
  763. assert db5.tables in ([], None)
  764. assert not (str(db5) in ("", None))
  765. dbdict6 = {"uri": DEFAULT_URI,
  766. "tables":[{"tablename": "staff"},
  767. {"tablename": "tvshow",
  768. "fields": [{"fieldname": "name"},
  769. {"fieldname": "rating", "type":"double"}
  770. ]
  771. }]
  772. }
  773. db6 = DAL(**dbdict6)
  774. assert len(db6["staff"].fields) == 1
  775. assert "name" in db6["tvshow"].fields
  776. assert db6.staff.insert() is not None
  777. assert isinstance(db6(db6.staff).select().first().id, long) == True
  778. drop(db6.staff)
  779. drop(db6.tvshow)
  780. db6.commit()
  781. @unittest.skipIf(IS_IMAP, "TODO: IMAP test")
  782. class TestValidateAndInsert(unittest.TestCase):
  783. def testRun(self):
  784. import datetime
  785. from gluon.validators import IS_INT_IN_RANGE
  786. db = DAL(DEFAULT_URI, check_reserved=['all'])
  787. db.define_table('val_and_insert',
  788. Field('aa'),
  789. Field('bb', 'integer',
  790. requires=IS_INT_IN_RANGE(1,5))
  791. )
  792. rtn = db.val_and_insert.validate_and_insert(aa='test1', bb=2)
  793. self.assertEqual(isinstance(rtn.id, long), True)
  794. #errors should be empty
  795. self.assertEqual(len(rtn.errors.keys()), 0)
  796. #this insert won't pass
  797. rtn = db.val_and_insert.validate_and_insert(bb="a")
  798. #the returned id should be None
  799. self.assertEqual(rtn.id, None)
  800. #an error message should be in rtn.errors.bb
  801. self.assertNotEqual(rtn.errors.bb, None)
  802. #cleanup table
  803. drop(db.val_and_insert)
  804. @unittest.skipIf(IS_IMAP, "TODO: IMAP test")
  805. class TestSelectAsDict(unittest.TestCase):
  806. def testSelect(self):
  807. db = DAL(DEFAULT_URI, check_reserved=['all'])
  808. db.define_table(
  809. 'a_table',
  810. Field('b_field'),
  811. Field('a_field'),
  812. )
  813. db.a_table.insert(a_field="aa1", b_field="bb1")
  814. rtn = db(db.a_table).select(db.a_table.id, db.a_table.b_field, db.a_table.a_field).as_list()
  815. self.assertEqual(rtn[0]['b_field'], 'bb1')
  816. keys = rtn[0].keys()
  817. self.assertEqual(len(keys), 3)
  818. self.assertEqual(("id" in keys, "b_field" in keys, "a_field" in keys), (True, True, True))
  819. drop(db.a_table)
  820. @unittest.skipIf(IS_IMAP, "TODO: IMAP test")
  821. class TestRNameTable(unittest.TestCase):
  822. #tests for highly experimental rname attribute
  823. @unittest.skipIf(IS_MONGODB, "TODO: MongoDB assertion error (long object has no attribute id)")
  824. def testSelect(self):
  825. db = DAL(DEFAULT_URI, check_reserved=['all'])
  826. rname = db._adapter.QUOTE_TEMPLATE % 'a very complicated tablename'
  827. db.define_table(
  828. 'easy_name',
  829. Field('a_field'),
  830. rname=rname
  831. )
  832. rtn = db.easy_name.insert(a_field='a')
  833. self.assertEqual(isinstance(rtn.id, long), True)
  834. rtn = db(db.easy_name.a_field == 'a').select()
  835. self.assertEqual(len(rtn), 1)
  836. self.assertEqual(isinstance(rtn[0].id, long), True)
  837. self.assertEqual(rtn[0].a_field, 'a')
  838. db.easy_name.insert(a_field='b')
  839. self.assertEqual(db(db.easy_name).count(), 2)
  840. rtn = db(db.easy_name.a_field == 'a').update(a_field='c')
  841. self.assertEqual(rtn, 1)
  842. #clean up
  843. drop(db.easy_name)
  844. @unittest.skip("JOIN queries are not supported")
  845. def testJoin(self):
  846. db = DAL(DEFAULT_URI, check_reserved=['all'])
  847. rname = db._adapter.QUOTE_TEMPLATE % 'this is table t1'
  848. rname2 = db._adapter.QUOTE_TEMPLATE % 'this is table t2'
  849. db.define_table('t1', Field('aa'), rname=rname)
  850. db.define_table('t2', Field('aa'), Field('b', db.t1), rname=rname2)
  851. i1 = db.t1.insert(aa='1')
  852. i2 = db.t1.insert(aa='2')
  853. i3 = db.t1.insert(aa='3')
  854. db.t2.insert(aa='4', b=i1)
  855. db.t2.insert(aa='5', b=i2)
  856. db.t2.insert(aa='6', b=i2)
  857. self.assertEqual(len(db(db.t1.id
  858. == db.t2.b).select(orderby=db.t1.aa
  859. | db.t2.aa)), 3)
  860. self.assertEqual(db(db.t1.id == db.t2.b).select(orderby=db.t1.aa
  861. | db.t2.aa)[2].t1.aa, '2')
  862. self.assertEqual(db(db.t1.id == db.t2.b).select(orderby=db.t1.aa
  863. | db.t2.aa)[2].t2.aa, '6')
  864. self.assertEqual(len(db().select(db.t1.ALL, db.t2.ALL,
  865. left=db.t2.on(db.t1.id == db.t2.b),
  866. orderby=db.t1.aa | db.t2.aa)), 4)
  867. self.assertEqual(db().select(db.t1.ALL, db.t2.ALL,
  868. left=db.t2.on(db.t1.id == db.t2.b),
  869. orderby=db.t1.aa | db.t2.aa)[2].t1.aa, '2')
  870. self.assertEqual(db().select(db.t1.ALL, db.t2.ALL,
  871. left=db.t2.on(db.t1.id == db.t2.b),
  872. orderby=db.t1.aa | db.t2.aa)[2].t2.aa, '6')
  873. self.assertEqual(db().select(db.t1.ALL, db.t2.ALL,
  874. left=db.t2.on(db.t1.id == db.t2.b),
  875. orderby=db.t1.aa | db.t2.aa)[3].t1.aa, '3')
  876. self.assertEqual(db().select(db.t1.ALL, db.t2.ALL,
  877. left=db.t2.on(db.t1.id == db.t2.b),
  878. orderby=db.t1.aa | db.t2.aa)[3].t2.aa, None)
  879. self.assertEqual(len(db().select(db.t1.aa, db.t2.id.count(),
  880. left=db.t2.on(db.t1.id == db.t2.b),
  881. orderby=db.t1.aa, groupby=db.t1.aa)),
  882. 3)
  883. self.assertEqual(db().select(db.t1.aa, db.t2.id.count(),
  884. left=db.t2.on(db.t1.id == db.t2.b),
  885. orderby=db.t1.aa,
  886. groupby=db.t1.aa)[0]._extra[db.t2.id.count()],
  887. 1)
  888. self.assertEqual(db().select(db.t1.aa, db.t2.id.count(),
  889. left=db.t2.on(db.t1.id == db.t2.b),
  890. orderby=db.t1.aa,
  891. groupby=db.t1.aa)[1]._extra[db.t2.id.count()],
  892. 2)
  893. self.assertEqual(db().select(db.t1.aa, db.t2.id.count(),
  894. left=db.t2.on(db.t1.id == db.t2.b),
  895. orderby=db.t1.aa,
  896. groupby=db.t1.aa)[2]._extra[db.t2.id.count()],
  897. 0)
  898. drop(db.t2)
  899. drop(db.t1)
  900. db.define_table('person',Field('name'), rname=rname)
  901. id = db.person.insert(name="max")
  902. self.assertEqual(id.name,'max')
  903. db.define_table('dog',Field('name'),Field('ownerperson','reference person'), rname=rname2)
  904. db.dog.insert(name='skipper',ownerperson=1)
  905. row = db(db.person.id==db.dog.ownerperson).select().first()
  906. self.assertEqual(row[db.person.name],'max')
  907. self.assertEqual(row['person.name'],'max')
  908. drop(db.dog)
  909. self.assertEqual(len(db.person._referenced_by),0)
  910. drop(db.person)
  911. @unittest.skipIf(IS_IMAP, "TODO: IMAP test")
  912. class TestRNameFields(unittest.TestCase):
  913. # tests for highly experimental rname attribute
  914. @unittest.skipIf(IS_GAE or IS_MONGODB, 'TODO: Datastore throws unsupported error for AGGREGATE. MongoDB assertion error (long object has no attribute id)')
  915. def testSelect(self):
  916. db = DAL(DEFAULT_URI, check_reserved=['all'])
  917. rname = db._adapter.QUOTE_TEMPLATE % 'a very complicated fieldname'
  918. rname2 = db._adapter.QUOTE_TEMPLATE % 'rrating from 1 to 10'
  919. db.define_table(
  920. 'easy_name',
  921. Field('a_field', rname=rname),
  922. Field('rating', 'integer', rname=rname2, default=2)
  923. )
  924. rtn = db.easy_name.insert(a_field='a')
  925. self.assertEqual(isinstance(rtn.id, long), True)
  926. rtn = db(db.easy_name.a_field == 'a').select()
  927. self.assertEqual(len(rtn), 1)
  928. self.assertEqual(isinstance(rtn[0].id, long), True)
  929. self.assertEqual(rtn[0].a_field, 'a')
  930. db.easy_name.insert(a_field='b')
  931. rtn = db(db.easy_name.id > 0).delete()
  932. self.assertEqual(rtn, 2)
  933. rtn = db(db.easy_name.id > 0).count()
  934. self.assertEqual(rtn, 0)
  935. db.easy_name.insert(a_field='a')
  936. db.easy_name.insert(a_field='b')
  937. rtn = db(db.easy_name.id > 0).count()
  938. self.assertEqual(rtn, 2)
  939. rtn = db(db.easy_name.a_field == 'a').update(a_field='c')
  940. rtn = db(db.easy_name.a_field == 'c').count()
  941. self.assertEqual(rtn, 1)
  942. rtn = db(db.easy_name.a_field != 'c').count()
  943. self.assertEqual(rtn, 1)
  944. avg = db.easy_name.id.avg()
  945. rtn = db(db.easy_name.id > 0).select(avg)
  946. self.assertEqual(rtn[0][avg], 3)
  947. avg = db.easy_name.rating.avg()
  948. rtn = db(db.easy_name.id > 0).select(avg)
  949. self.assertEqual(rtn[0][avg], 2)
  950. rname = db._adapter.QUOTE_TEMPLATE % 'this is the person name'
  951. db.define_table(
  952. 'person',
  953. Field('name', default="Michael", rname=rname),
  954. Field('uuid')
  955. )
  956. michael = db.person.insert() #default insert
  957. john = db.person.insert(name='John')
  958. luke = db.person.insert(name='Luke')
  959. self.assertEqual(len(rtn), 3)
  960. self.assertEqual(rtn[0].id, michael)
  961. self.assertEqual(rtn[0].name, 'Michael')
  962. self.assertEqual(rtn[1].id, john)
  963. self.assertEqual(rtn[1].name, 'John')
  964. #fetch owners, eventually with pet
  965. #main point is retrieving Luke with no pets
  966. rtn = db(db.person.id > 0).select()
  967. self.assertEqual(rtn[0].id, michael)
  968. self.assertEqual(rtn[0].name, 'Michael')
  969. self.assertEqual(rtn[3].name, 'Luke')
  970. self.assertEqual(rtn[3].id, luke)
  971. #as dict
  972. rtn = db(db.person.id > 0).select().as_dict()
  973. self.assertEqual(rtn[1]['name'], 'Michael')
  974. #as list
  975. rtn = db(db.person.id > 0).select().as_list()
  976. self.assertEqual(rtn[0]['name'], 'Michael')
  977. #isempty
  978. rtn = db(db.person.id > 0).isempty()
  979. self.assertEqual(rtn, False)
  980. #aliases
  981. rname = db._adapter.QUOTE_TEMPLATE % 'the cub name'
  982. if DEFAULT_URI.startswith('mssql'):
  983. #multiple cascade gotcha
  984. for key in ['reference','reference FK']:
  985. db._adapter.types[key]=db._adapter.types[key].replace(
  986. '%(on_delete_action)s','NO ACTION')
  987. db.define_table('pet_farm',
  988. Field('name', rname=rname),
  989. Field('father','reference pet_farm'),
  990. Field('mother','reference pet_farm'),
  991. )
  992. minali = db.pet_farm.insert(name='Minali')
  993. osbert = db.pet_farm.insert(name='Osbert')
  994. #they had a cub
  995. selina = db.pet_farm.insert(name='Selina', father=osbert, mother=minali)
  996. father = db.pet_farm.with_alias('father')
  997. mother = db.pet_farm.with_alias('mother')
  998. #fetch pets with relatives
  999. rtn = db().select(
  1000. db.pet_farm.name, father.name, mother.name,
  1001. left=[
  1002. father.on(father.id == db.pet_farm.father),
  1003. mother.on(mother.id == db.pet_farm.mother)
  1004. ],
  1005. orderby=db.pet_farm.id
  1006. )
  1007. self.assertEqual(len(rtn), 3)
  1008. self.assertEqual(rtn[0].pet_farm.name, 'Minali')
  1009. self.assertEqual(rtn[0].father.name, None)
  1010. self.assertEqual(rtn[0].mother.name, None)
  1011. self.assertEqual(rtn[1].pet_farm.name, 'Osbert')
  1012. self.assertEqual(rtn[2].pet_farm.name, 'Selina')
  1013. self.assertEqual(rtn[2].father.name, 'Osbert')
  1014. self.assertEqual(rtn[2].mother.name, 'Minali')
  1015. #clean up
  1016. drop(db.pet_farm)
  1017. drop(db.person)
  1018. drop(db.easy_name)
  1019. @unittest.skipIf(IS_GAE or IS_MONGODB, 'TODO: Datastore does not accept dict objects as json field input. MongoDB assertionerror Binary("x", 0) != "x"')
  1020. def testRun(self):
  1021. db = DAL(DEFAULT_URI, check_reserved=['all'])
  1022. rname = db._adapter.QUOTE_TEMPLATE % 'a very complicated fieldname'
  1023. for ft in ['string', 'text', 'password', 'upload', 'blob']:
  1024. db.define_table('tt', Field('aa', ft, default='', rname=rname))
  1025. self.assertEqual(isinstance(db.tt.insert(aa='x'), long), True)
  1026. self.assertEqual(db().select(db.tt.aa)[0].aa, 'x')
  1027. drop(db.tt)
  1028. db.define_table('tt', Field('aa', 'integer', default=1, rname=rname))
  1029. self.assertEqual(isinstance(db.tt.insert(aa=3), long), True)
  1030. self.assertEqual(db().select(db.tt.aa)[0].aa, 3)
  1031. drop(db.tt)
  1032. db.define_table('tt', Field('aa', 'double', default=1, rname=rname))
  1033. self.assertEqual(isinstance(db.tt.insert(aa=3.1), long), True)
  1034. self.assertEqual(db().select(db.tt.aa)[0].aa, 3.1)
  1035. drop(db.tt)
  1036. db.define_table('tt', Field('aa', 'boolean', default=True, rname=rname))
  1037. self.assertEqual(isinstance(db.tt.insert(aa=True), long), True)
  1038. self.assertEqual(db().select(db.tt.aa)[0].aa, True)
  1039. drop(db.tt)
  1040. db.define_table('tt', Field('aa', 'json', default={}, rname=rname))
  1041. self.assertEqual(isinstance(db.tt.insert(aa={}), long), True)
  1042. self.assertEqual(db().select(db.tt.aa)[0].aa, {})
  1043. drop(db.tt)
  1044. db.define_table('tt', Field('aa', 'date',
  1045. default=datetime.date.today(), rname=rname))
  1046. t0 = datetime.date.today()
  1047. self.assertEqual(isinstance(db.tt.insert(aa=t0), long), True)
  1048. self.assertEqual(db().select(db.tt.aa)[0].aa, t0)
  1049. drop(db.tt)
  1050. db.define_table('tt', Field('aa', 'datetime',
  1051. default=datetime.datetime.today(), rname=rname))
  1052. t0 = datetime.datetime(
  1053. 1971,
  1054. 12,
  1055. 21,
  1056. 10,
  1057. 30,
  1058. 55,
  1059. 0,
  1060. )
  1061. self.assertEqual(db.tt.insert(aa=t0), 1)
  1062. self.assertEqual(db().select(db.tt.aa)[0].aa, t0)
  1063. ## Row APIs
  1064. row = db().select(db.tt.aa)[0]
  1065. self.assertEqual(db.tt[1].aa,t0)
  1066. self.assertEqual(db.tt['aa'],db.tt.aa)
  1067. self.assertEqual(db.tt(1).aa,t0)
  1068. self.assertTrue(db.tt(1,aa=None

Large files files are truncated, but you can click here to view the full file