PageRenderTime 31ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/gluon/tests/test_dal.py

https://github.com/eddgt/web2py
Python | 1520 lines | 1506 code | 3 blank | 11 comment | 4 complexity | 6cabfcbc6f6379028a4bd3fad33c6b4f MD5 | raw file
Possible License(s): BSD-2-Clause, AGPL-3.0, LGPL-3.0
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. """
  4. Unit tests for gluon.dal
  5. """
  6. import sys
  7. import os
  8. import glob
  9. import unittest
  10. import datetime
  11. try:
  12. import cStringIO as StringIO
  13. except:
  14. from io import StringIO
  15. def fix_sys_path():
  16. """
  17. logic to have always the correct sys.path
  18. '', web2py/gluon, web2py/site-packages, web2py/ ...
  19. """
  20. def add_path_first(path):
  21. sys.path = [path] + [p for p in sys.path if (
  22. not p == path and not p == (path + '/'))]
  23. path = os.path.dirname(os.path.abspath(__file__))
  24. if not os.path.isfile(os.path.join(path,'web2py.py')):
  25. i = 0
  26. while i<10:
  27. i += 1
  28. if os.path.exists(os.path.join(path,'web2py.py')):
  29. break
  30. path = os.path.abspath(os.path.join(path, '..'))
  31. paths = [path,
  32. os.path.abspath(os.path.join(path, 'site-packages')),
  33. os.path.abspath(os.path.join(path, 'gluon')),
  34. '']
  35. [add_path_first(path) for path in paths]
  36. fix_sys_path()
  37. #for travis-ci
  38. DEFAULT_URI = os.environ.get('DB', 'sqlite:memory')
  39. print 'Testing against %s engine (%s)' % (DEFAULT_URI.partition(':')[0], DEFAULT_URI)
  40. from dal import DAL, Field, Table, SQLALL
  41. ALLOWED_DATATYPES = [
  42. 'string',
  43. 'text',
  44. 'integer',
  45. 'boolean',
  46. 'double',
  47. 'blob',
  48. 'date',
  49. 'time',
  50. 'datetime',
  51. 'upload',
  52. 'password',
  53. 'json',
  54. ]
  55. def setUpModule():
  56. pass
  57. def tearDownModule():
  58. if os.path.isfile('sql.log'):
  59. os.unlink('sql.log')
  60. for a in glob.glob('*.table'):
  61. os.unlink(a)
  62. class TestFields(unittest.TestCase):
  63. def testFieldName(self):
  64. # Check that Fields cannot start with underscores
  65. self.assertRaises(SyntaxError, Field, '_abc', 'string')
  66. # Check that Fields cannot contain punctuation other than underscores
  67. self.assertRaises(SyntaxError, Field, 'a.bc', 'string')
  68. # Check that Fields cannot be a name of a method or property of Table
  69. for x in ['drop', 'on', 'truncate']:
  70. self.assertRaises(SyntaxError, Field, x, 'string')
  71. # Check that Fields allows underscores in the body of a field name.
  72. self.assert_(Field('a_bc', 'string'),
  73. "Field isn't allowing underscores in fieldnames. It should.")
  74. def testFieldTypes(self):
  75. # Check that string, and password default length is 512
  76. for typ in ['string', 'password']:
  77. self.assert_(Field('abc', typ).length == 512,
  78. "Default length for type '%s' is not 512 or 255" % typ)
  79. # Check that upload default length is 512
  80. self.assert_(Field('abc', 'upload').length == 512,
  81. "Default length for type 'upload' is not 512")
  82. # Check that Tables passed in the type creates a reference
  83. self.assert_(Field('abc', Table(None, 'temp')).type
  84. == 'reference temp',
  85. 'Passing an Table does not result in a reference type.')
  86. def testFieldLabels(self):
  87. # Check that a label is successfully built from the supplied fieldname
  88. self.assert_(Field('abc', 'string').label == 'Abc',
  89. 'Label built is incorrect')
  90. self.assert_(Field('abc_def', 'string').label == 'Abc Def',
  91. 'Label built is incorrect')
  92. def testFieldFormatters(self): # Formatter should be called Validator
  93. # Test the default formatters
  94. for typ in ALLOWED_DATATYPES:
  95. f = Field('abc', typ)
  96. if typ not in ['date', 'time', 'datetime']:
  97. isinstance(f.formatter('test'), str)
  98. else:
  99. isinstance(f.formatter(datetime.datetime.now()), str)
  100. def testRun(self):
  101. db = DAL(DEFAULT_URI, check_reserved=['all'])
  102. for ft in ['string', 'text', 'password', 'upload', 'blob']:
  103. db.define_table('tt', Field('aa', ft, default=''))
  104. self.assertEqual(db.tt.insert(aa='x'), 1)
  105. self.assertEqual(db().select(db.tt.aa)[0].aa, 'x')
  106. db.tt.drop()
  107. db.define_table('tt', Field('aa', 'integer', default=1))
  108. self.assertEqual(db.tt.insert(aa=3), 1)
  109. self.assertEqual(db().select(db.tt.aa)[0].aa, 3)
  110. db.tt.drop()
  111. db.define_table('tt', Field('aa', 'double', default=1))
  112. self.assertEqual(db.tt.insert(aa=3.1), 1)
  113. self.assertEqual(db().select(db.tt.aa)[0].aa, 3.1)
  114. db.tt.drop()
  115. db.define_table('tt', Field('aa', 'boolean', default=True))
  116. self.assertEqual(db.tt.insert(aa=True), 1)
  117. self.assertEqual(db().select(db.tt.aa)[0].aa, True)
  118. db.tt.drop()
  119. db.define_table('tt', Field('aa', 'json', default={}))
  120. self.assertEqual(db.tt.insert(aa={}), 1)
  121. self.assertEqual(db().select(db.tt.aa)[0].aa, {})
  122. db.tt.drop()
  123. db.define_table('tt', Field('aa', 'date',
  124. default=datetime.date.today()))
  125. t0 = datetime.date.today()
  126. self.assertEqual(db.tt.insert(aa=t0), 1)
  127. self.assertEqual(db().select(db.tt.aa)[0].aa, t0)
  128. db.tt.drop()
  129. db.define_table('tt', Field('aa', 'datetime',
  130. default=datetime.datetime.today()))
  131. t0 = datetime.datetime(
  132. 1971,
  133. 12,
  134. 21,
  135. 10,
  136. 30,
  137. 55,
  138. 0,
  139. )
  140. self.assertEqual(db.tt.insert(aa=t0), 1)
  141. self.assertEqual(db().select(db.tt.aa)[0].aa, t0)
  142. ## Row APIs
  143. row = db().select(db.tt.aa)[0]
  144. self.assertEqual(db.tt[1].aa,t0)
  145. self.assertEqual(db.tt['aa'],db.tt.aa)
  146. self.assertEqual(db.tt(1).aa,t0)
  147. self.assertTrue(db.tt(1,aa=None)==None)
  148. self.assertFalse(db.tt(1,aa=t0)==None)
  149. self.assertEqual(row.aa,t0)
  150. self.assertEqual(row['aa'],t0)
  151. self.assertEqual(row['tt.aa'],t0)
  152. self.assertEqual(row('tt.aa'),t0)
  153. ## Lazy and Virtual fields
  154. db.tt.b = Field.Virtual(lambda row: row.tt.aa)
  155. db.tt.c = Field.Lazy(lambda row: row.tt.aa)
  156. row = db().select(db.tt.aa)[0]
  157. self.assertEqual(row.b,t0)
  158. self.assertEqual(row.c(),t0)
  159. db.tt.drop()
  160. db.define_table('tt', Field('aa', 'time', default='11:30'))
  161. t0 = datetime.time(10, 30, 55)
  162. self.assertEqual(db.tt.insert(aa=t0), 1)
  163. self.assertEqual(db().select(db.tt.aa)[0].aa, t0)
  164. db.tt.drop()
  165. class TestTables(unittest.TestCase):
  166. def testTableNames(self):
  167. # Check that Tables cannot start with underscores
  168. self.assertRaises(SyntaxError, Table, None, '_abc')
  169. # Check that Tables cannot contain punctuation other than underscores
  170. self.assertRaises(SyntaxError, Table, None, 'a.bc')
  171. # Check that Tables cannot be a name of a method or property of DAL
  172. for x in ['define_table', 'tables', 'as_dict']:
  173. self.assertRaises(SyntaxError, Table, None, x)
  174. # Check that Table allows underscores in the body of a field name.
  175. self.assert_(Table(None, 'a_bc'),
  176. "Table isn't allowing underscores in tablename. It should.")
  177. class TestAll(unittest.TestCase):
  178. def setUp(self):
  179. self.pt = Table(None,'PseudoTable',Field('name'),Field('birthdate'))
  180. def testSQLALL(self):
  181. ans = 'PseudoTable.id, PseudoTable.name, PseudoTable.birthdate'
  182. self.assertEqual(str(SQLALL(self.pt)), ans)
  183. class TestTable(unittest.TestCase):
  184. def testTableCreation(self):
  185. # Check for error when not passing type other than Field or Table
  186. self.assertRaises(SyntaxError, Table, None, 'test', None)
  187. persons = Table(None, 'persons',
  188. Field('firstname','string'),
  189. Field('lastname', 'string'))
  190. # Does it have the correct fields?
  191. self.assert_(set(persons.fields).issuperset(set(['firstname',
  192. 'lastname'])))
  193. # ALL is set correctly
  194. self.assert_('persons.firstname, persons.lastname'
  195. in str(persons.ALL))
  196. def testTableAlias(self):
  197. db = DAL(DEFAULT_URI, check_reserved=['all'])
  198. persons = Table(db, 'persons', Field('firstname',
  199. 'string'), Field('lastname', 'string'))
  200. aliens = persons.with_alias('aliens')
  201. # Are the different table instances with the same fields
  202. self.assert_(persons is not aliens)
  203. self.assert_(set(persons.fields) == set(aliens.fields))
  204. def testTableInheritance(self):
  205. persons = Table(None, 'persons', Field('firstname',
  206. 'string'), Field('lastname', 'string'))
  207. customers = Table(None, 'customers',
  208. Field('items_purchased', 'integer'),
  209. persons)
  210. self.assert_(set(customers.fields).issuperset(set(
  211. ['items_purchased', 'firstname', 'lastname'])))
  212. class TestInsert(unittest.TestCase):
  213. def testRun(self):
  214. db = DAL(DEFAULT_URI, check_reserved=['all'])
  215. db.define_table('tt', Field('aa'))
  216. self.assertEqual(db.tt.insert(aa='1'), 1)
  217. self.assertEqual(db.tt.insert(aa='1'), 2)
  218. self.assertEqual(db.tt.insert(aa='1'), 3)
  219. self.assertEqual(db(db.tt.aa == '1').count(), 3)
  220. self.assertEqual(db(db.tt.aa == '2').isempty(), True)
  221. self.assertEqual(db(db.tt.aa == '1').update(aa='2'), 3)
  222. self.assertEqual(db(db.tt.aa == '2').count(), 3)
  223. self.assertEqual(db(db.tt.aa == '2').isempty(), False)
  224. self.assertEqual(db(db.tt.aa == '2').delete(), 3)
  225. self.assertEqual(db(db.tt.aa == '2').isempty(), True)
  226. db.tt.drop()
  227. class TestSelect(unittest.TestCase):
  228. def testRun(self):
  229. db = DAL(DEFAULT_URI, check_reserved=['all'])
  230. db.define_table('tt', Field('aa'))
  231. self.assertEqual(db.tt.insert(aa='1'), 1)
  232. self.assertEqual(db.tt.insert(aa='2'), 2)
  233. self.assertEqual(db.tt.insert(aa='3'), 3)
  234. self.assertEqual(db(db.tt.id > 0).count(), 3)
  235. self.assertEqual(db(db.tt.id > 0).select(orderby=~db.tt.aa
  236. | db.tt.id)[0].aa, '3')
  237. self.assertEqual(len(db(db.tt.id > 0).select(limitby=(1, 2))), 1)
  238. self.assertEqual(db(db.tt.id > 0).select(limitby=(1, 2))[0].aa,
  239. '2')
  240. self.assertEqual(len(db().select(db.tt.ALL)), 3)
  241. self.assertEqual(db(db.tt.aa == None).count(), 0)
  242. self.assertEqual(db(db.tt.aa != None).count(), 3)
  243. self.assertEqual(db(db.tt.aa > '1').count(), 2)
  244. self.assertEqual(db(db.tt.aa >= '1').count(), 3)
  245. self.assertEqual(db(db.tt.aa == '1').count(), 1)
  246. self.assertEqual(db(db.tt.aa != '1').count(), 2)
  247. self.assertEqual(db(db.tt.aa < '3').count(), 2)
  248. self.assertEqual(db(db.tt.aa <= '3').count(), 3)
  249. self.assertEqual(db(db.tt.aa > '1')(db.tt.aa < '3').count(), 1)
  250. self.assertEqual(db((db.tt.aa > '1') & (db.tt.aa < '3')).count(), 1)
  251. self.assertEqual(db((db.tt.aa > '1') | (db.tt.aa < '3')).count(), 3)
  252. self.assertEqual(db((db.tt.aa > '1') & ~(db.tt.aa > '2')).count(), 1)
  253. self.assertEqual(db(~(db.tt.aa > '1') & (db.tt.aa > '2')).count(), 0)
  254. db.tt.drop()
  255. class TestAddMethod(unittest.TestCase):
  256. def testRun(self):
  257. db = DAL(DEFAULT_URI, check_reserved=['all'])
  258. db.define_table('tt', Field('aa'))
  259. @db.tt.add_method.all
  260. def select_all(table,orderby=None):
  261. return table._db(table).select(orderby=orderby)
  262. self.assertEqual(db.tt.insert(aa='1'), 1)
  263. self.assertEqual(db.tt.insert(aa='2'), 2)
  264. self.assertEqual(db.tt.insert(aa='3'), 3)
  265. self.assertEqual(len(db.tt.all()), 3)
  266. db.tt.drop()
  267. class TestBelongs(unittest.TestCase):
  268. def testRun(self):
  269. db = DAL(DEFAULT_URI, check_reserved=['all'])
  270. db.define_table('tt', Field('aa'))
  271. self.assertEqual(db.tt.insert(aa='1'), 1)
  272. self.assertEqual(db.tt.insert(aa='2'), 2)
  273. self.assertEqual(db.tt.insert(aa='3'), 3)
  274. self.assertEqual(db(db.tt.aa.belongs(('1', '3'))).count(),
  275. 2)
  276. self.assertEqual(db(db.tt.aa.belongs(db(db.tt.id
  277. > 2)._select(db.tt.aa))).count(), 1)
  278. self.assertEqual(db(db.tt.aa.belongs(db(db.tt.aa.belongs(('1',
  279. '3')))._select(db.tt.aa))).count(), 2)
  280. self.assertEqual(db(db.tt.aa.belongs(db(db.tt.aa.belongs(db
  281. (db.tt.aa.belongs(('1', '3')))._select(db.tt.aa)))._select(
  282. db.tt.aa))).count(),
  283. 2)
  284. db.tt.drop()
  285. class TestContains(unittest.TestCase):
  286. def testRun(self):
  287. db = DAL(DEFAULT_URI, check_reserved=['all'])
  288. db.define_table('tt', Field('aa', 'list:string'), Field('bb','string'))
  289. self.assertEqual(db.tt.insert(aa=['aaa','bbb'],bb='aaa'), 1)
  290. self.assertEqual(db.tt.insert(aa=['bbb','ddd'],bb='abb'), 2)
  291. self.assertEqual(db.tt.insert(aa=['eee','aaa'],bb='acc'), 3)
  292. self.assertEqual(db(db.tt.aa.contains('aaa')).count(), 2)
  293. self.assertEqual(db(db.tt.aa.contains('bbb')).count(), 2)
  294. self.assertEqual(db(db.tt.aa.contains('aa')).count(), 0)
  295. self.assertEqual(db(db.tt.bb.contains('a')).count(), 3)
  296. self.assertEqual(db(db.tt.bb.contains('b')).count(), 1)
  297. self.assertEqual(db(db.tt.bb.contains('d')).count(), 0)
  298. self.assertEqual(db(db.tt.aa.contains(db.tt.bb)).count(), 1)
  299. db.tt.drop()
  300. class TestLike(unittest.TestCase):
  301. def testRun(self):
  302. db = DAL(DEFAULT_URI, check_reserved=['all'])
  303. db.define_table('tt', Field('aa'))
  304. self.assertEqual(db.tt.insert(aa='abc'), 1)
  305. self.assertEqual(db(db.tt.aa.like('a%')).count(), 1)
  306. self.assertEqual(db(db.tt.aa.like('%b%')).count(), 1)
  307. self.assertEqual(db(db.tt.aa.like('%c')).count(), 1)
  308. self.assertEqual(db(db.tt.aa.like('%d%')).count(), 0)
  309. self.assertEqual(db(db.tt.aa.lower().like('A%')).count(), 1)
  310. self.assertEqual(db(db.tt.aa.lower().like('%B%')).count(),
  311. 1)
  312. self.assertEqual(db(db.tt.aa.lower().like('%C')).count(), 1)
  313. self.assertEqual(db(db.tt.aa.upper().like('A%')).count(), 1)
  314. self.assertEqual(db(db.tt.aa.upper().like('%B%')).count(),
  315. 1)
  316. self.assertEqual(db(db.tt.aa.upper().like('%C')).count(), 1)
  317. db.tt.drop()
  318. db.define_table('tt', Field('aa', 'integer'))
  319. self.assertEqual(db.tt.insert(aa=1111111111), 1)
  320. self.assertEqual(db(db.tt.aa.like('1%')).count(), 1)
  321. self.assertEqual(db(db.tt.aa.like('2%')).count(), 0)
  322. db.tt.drop()
  323. class TestDatetime(unittest.TestCase):
  324. def testRun(self):
  325. db = DAL(DEFAULT_URI, check_reserved=['all'])
  326. db.define_table('tt', Field('aa', 'datetime'))
  327. self.assertEqual(db.tt.insert(aa=datetime.datetime(1971, 12, 21,
  328. 11, 30)), 1)
  329. self.assertEqual(db.tt.insert(aa=datetime.datetime(1971, 11, 21,
  330. 10, 30)), 2)
  331. self.assertEqual(db.tt.insert(aa=datetime.datetime(1970, 12, 21,
  332. 9, 30)), 3)
  333. self.assertEqual(db(db.tt.aa == datetime.datetime(1971, 12,
  334. 21, 11, 30)).count(), 1)
  335. self.assertEqual(db(db.tt.aa.year() == 1971).count(), 2)
  336. self.assertEqual(db(db.tt.aa.month() == 12).count(), 2)
  337. self.assertEqual(db(db.tt.aa.day() == 21).count(), 3)
  338. self.assertEqual(db(db.tt.aa.hour() == 11).count(), 1)
  339. self.assertEqual(db(db.tt.aa.minutes() == 30).count(), 3)
  340. self.assertEqual(db(db.tt.aa.seconds() == 0).count(), 3)
  341. self.assertEqual(db(db.tt.aa.epoch()<365*24*3600).count(),1)
  342. db.tt.drop()
  343. class TestExpressions(unittest.TestCase):
  344. def testRun(self):
  345. db = DAL(DEFAULT_URI, check_reserved=['all'])
  346. db.define_table('tt', Field('aa', 'integer'))
  347. self.assertEqual(db.tt.insert(aa=1), 1)
  348. self.assertEqual(db.tt.insert(aa=2), 2)
  349. self.assertEqual(db.tt.insert(aa=3), 3)
  350. self.assertEqual(db(db.tt.aa == 3).update(aa=db.tt.aa + 1), 1)
  351. self.assertEqual(db(db.tt.aa == 4).count(), 1)
  352. self.assertEqual(db(db.tt.aa == -2).count(), 0)
  353. sum = (db.tt.aa + 1).sum()
  354. self.assertEqual(db(db.tt.aa == 2).select(sum).first()[sum], 3)
  355. self.assertEqual(db(db.tt.aa == -2).select(sum).first()[sum], None)
  356. db.tt.drop()
  357. class TestJoin(unittest.TestCase):
  358. def testRun(self):
  359. db = DAL(DEFAULT_URI, check_reserved=['all'])
  360. db.define_table('t1', Field('aa'))
  361. db.define_table('t2', Field('aa'), Field('b', db.t1))
  362. i1 = db.t1.insert(aa='1')
  363. i2 = db.t1.insert(aa='2')
  364. i3 = db.t1.insert(aa='3')
  365. db.t2.insert(aa='4', b=i1)
  366. db.t2.insert(aa='5', b=i2)
  367. db.t2.insert(aa='6', b=i2)
  368. self.assertEqual(len(db(db.t1.id
  369. == db.t2.b).select(orderby=db.t1.aa
  370. | db.t2.aa)), 3)
  371. self.assertEqual(db(db.t1.id == db.t2.b).select(orderby=db.t1.aa
  372. | db.t2.aa)[2].t1.aa, '2')
  373. self.assertEqual(db(db.t1.id == db.t2.b).select(orderby=db.t1.aa
  374. | db.t2.aa)[2].t2.aa, '6')
  375. self.assertEqual(len(db().select(db.t1.ALL, db.t2.ALL,
  376. left=db.t2.on(db.t1.id == db.t2.b),
  377. orderby=db.t1.aa | db.t2.aa)), 4)
  378. self.assertEqual(db().select(db.t1.ALL, db.t2.ALL,
  379. left=db.t2.on(db.t1.id == db.t2.b),
  380. orderby=db.t1.aa | db.t2.aa)[2].t1.aa, '2')
  381. self.assertEqual(db().select(db.t1.ALL, db.t2.ALL,
  382. left=db.t2.on(db.t1.id == db.t2.b),
  383. orderby=db.t1.aa | db.t2.aa)[2].t2.aa, '6')
  384. self.assertEqual(db().select(db.t1.ALL, db.t2.ALL,
  385. left=db.t2.on(db.t1.id == db.t2.b),
  386. orderby=db.t1.aa | db.t2.aa)[3].t1.aa, '3')
  387. self.assertEqual(db().select(db.t1.ALL, db.t2.ALL,
  388. left=db.t2.on(db.t1.id == db.t2.b),
  389. orderby=db.t1.aa | db.t2.aa)[3].t2.aa, None)
  390. self.assertEqual(len(db().select(db.t1.aa, db.t2.id.count(),
  391. left=db.t2.on(db.t1.id == db.t2.b),
  392. orderby=db.t1.aa, groupby=db.t1.aa)),
  393. 3)
  394. self.assertEqual(db().select(db.t1.aa, db.t2.id.count(),
  395. left=db.t2.on(db.t1.id == db.t2.b),
  396. orderby=db.t1.aa,
  397. groupby=db.t1.aa)[0]._extra[db.t2.id.count()],
  398. 1)
  399. self.assertEqual(db().select(db.t1.aa, db.t2.id.count(),
  400. left=db.t2.on(db.t1.id == db.t2.b),
  401. orderby=db.t1.aa,
  402. groupby=db.t1.aa)[1]._extra[db.t2.id.count()],
  403. 2)
  404. self.assertEqual(db().select(db.t1.aa, db.t2.id.count(),
  405. left=db.t2.on(db.t1.id == db.t2.b),
  406. orderby=db.t1.aa,
  407. groupby=db.t1.aa)[2]._extra[db.t2.id.count()],
  408. 0)
  409. db.t2.drop()
  410. db.t1.drop()
  411. db.define_table('person',Field('name'))
  412. id = db.person.insert(name="max")
  413. self.assertEqual(id.name,'max')
  414. db.define_table('dog',Field('name'),Field('ownerperson','reference person'))
  415. db.dog.insert(name='skipper',ownerperson=1)
  416. row = db(db.person.id==db.dog.ownerperson).select().first()
  417. self.assertEqual(row[db.person.name],'max')
  418. self.assertEqual(row['person.name'],'max')
  419. db.dog.drop()
  420. self.assertEqual(len(db.person._referenced_by),0)
  421. db.person.drop()
  422. class TestMinMaxSumAvg(unittest.TestCase):
  423. def testRun(self):
  424. db = DAL(DEFAULT_URI, check_reserved=['all'])
  425. db.define_table('tt', Field('aa', 'integer'))
  426. self.assertEqual(db.tt.insert(aa=1), 1)
  427. self.assertEqual(db.tt.insert(aa=2), 2)
  428. self.assertEqual(db.tt.insert(aa=3), 3)
  429. s = db.tt.aa.min()
  430. self.assertEqual(db(db.tt.id > 0).select(s)[0]._extra[s], 1)
  431. self.assertEqual(db(db.tt.id > 0).select(s).first()[s], 1)
  432. self.assertEqual(db().select(s).first()[s], 1)
  433. s = db.tt.aa.max()
  434. self.assertEqual(db().select(s).first()[s], 3)
  435. s = db.tt.aa.sum()
  436. self.assertEqual(db().select(s).first()[s], 6)
  437. s = db.tt.aa.count()
  438. self.assertEqual(db().select(s).first()[s], 3)
  439. s = db.tt.aa.avg()
  440. self.assertEqual(db().select(s).first()[s], 2)
  441. db.tt.drop()
  442. class TestCache(unittest.TestCase):
  443. def testRun(self):
  444. from cache import CacheInRam
  445. cache = CacheInRam()
  446. db = DAL(DEFAULT_URI, check_reserved=['all'])
  447. db.define_table('tt', Field('aa'))
  448. db.tt.insert(aa='1')
  449. r0 = db().select(db.tt.ALL)
  450. r1 = db().select(db.tt.ALL, cache=(cache, 1000))
  451. self.assertEqual(len(r0),len(r1))
  452. r2 = db().select(db.tt.ALL, cache=(cache, 1000))
  453. self.assertEqual(len(r0),len(r2))
  454. r3 = db().select(db.tt.ALL, cache=(cache, 1000), cacheable=True)
  455. self.assertEqual(len(r0),len(r3))
  456. r4 = db().select(db.tt.ALL, cache=(cache, 1000), cacheable=True)
  457. self.assertEqual(len(r0),len(r4))
  458. db.tt.drop()
  459. class TestMigrations(unittest.TestCase):
  460. def testRun(self):
  461. db = DAL(DEFAULT_URI, check_reserved=['all'])
  462. db.define_table('tt', Field('aa'), migrate='.storage.table')
  463. db.commit()
  464. db.close()
  465. db = DAL(DEFAULT_URI, check_reserved=['all'])
  466. db.define_table('tt', Field('aa'), Field('b'),
  467. migrate='.storage.table')
  468. db.commit()
  469. db.close()
  470. db = DAL(DEFAULT_URI, check_reserved=['all'])
  471. db.define_table('tt', Field('aa'), Field('b', 'text'),
  472. migrate='.storage.table')
  473. db.commit()
  474. db.close()
  475. db = DAL(DEFAULT_URI, check_reserved=['all'])
  476. db.define_table('tt', Field('aa'), migrate='.storage.table')
  477. db.tt.drop()
  478. db.commit()
  479. db.close()
  480. def tearDown(self):
  481. if os.path.exists('.storage.db'):
  482. os.unlink('.storage.db')
  483. if os.path.exists('.storage.table'):
  484. os.unlink('.storage.table')
  485. class TestReference(unittest.TestCase):
  486. def testRun(self):
  487. db = DAL(DEFAULT_URI, check_reserved=['all'])
  488. if DEFAULT_URI.startswith('mssql'):
  489. #multiple cascade gotcha
  490. for key in ['reference','reference FK']:
  491. db._adapter.types[key]=db._adapter.types[key].replace(
  492. '%(on_delete_action)s','NO ACTION')
  493. db.define_table('tt', Field('name'), Field('aa','reference tt'))
  494. db.commit()
  495. x = db.tt.insert(name='max')
  496. assert x.id == 1
  497. assert x['id'] == 1
  498. x.aa = x
  499. assert x.aa == 1
  500. x.update_record()
  501. y = db.tt[1]
  502. assert y.aa == 1
  503. assert y.aa.aa.aa.aa.aa.aa.name == 'max'
  504. z=db.tt.insert(name='xxx', aa = y)
  505. assert z.aa == y.id
  506. db.tt.drop()
  507. db.commit()
  508. class TestClientLevelOps(unittest.TestCase):
  509. def testRun(self):
  510. db = DAL(DEFAULT_URI, check_reserved=['all'])
  511. db.define_table('tt', Field('aa'))
  512. db.commit()
  513. db.tt.insert(aa="test")
  514. rows1 = db(db.tt.id>0).select()
  515. rows2 = db(db.tt.id>0).select()
  516. rows3 = rows1 & rows2
  517. assert len(rows3) == 2
  518. rows4 = rows1 | rows2
  519. assert len(rows4) == 1
  520. rows5 = rows1.find(lambda row: row.aa=="test")
  521. assert len(rows5) == 1
  522. rows6 = rows2.exclude(lambda row: row.aa=="test")
  523. assert len(rows6) == 1
  524. rows7 = rows5.sort(lambda row: row.aa)
  525. assert len(rows7) == 1
  526. db.tt.drop()
  527. db.commit()
  528. class TestVirtualFields(unittest.TestCase):
  529. def testRun(self):
  530. db = DAL(DEFAULT_URI, check_reserved=['all'])
  531. db.define_table('tt', Field('aa'))
  532. db.commit()
  533. db.tt.insert(aa="test")
  534. class Compute:
  535. def a_upper(row): return row.tt.aa.upper()
  536. db.tt.virtualfields.append(Compute())
  537. assert db(db.tt.id>0).select().first().a_upper == 'TEST'
  538. db.tt.drop()
  539. db.commit()
  540. class TestComputedFields(unittest.TestCase):
  541. def testRun(self):
  542. db = DAL(DEFAULT_URI, check_reserved=['all'])
  543. db.define_table('tt',
  544. Field('aa'),
  545. Field('bb',default='x'),
  546. Field('cc',compute=lambda r: r.aa+r.bb))
  547. db.commit()
  548. id = db.tt.insert(aa="z")
  549. self.assertEqual(db.tt[id].cc,'zx')
  550. db.tt.drop()
  551. db.commit()
  552. # test checking that a compute field can refer to earlier-defined computed fields
  553. db.define_table('tt',
  554. Field('aa'),
  555. Field('bb',default='x'),
  556. Field('cc',compute=lambda r: r.aa+r.bb),
  557. Field('dd',compute=lambda r: r.bb + r.cc))
  558. db.commit()
  559. id = db.tt.insert(aa="z")
  560. self.assertEqual(db.tt[id].dd,'xzx')
  561. db.tt.drop()
  562. db.commit()
  563. class TestCommonFilters(unittest.TestCase):
  564. def testRun(self):
  565. db = DAL(DEFAULT_URI, check_reserved=['all'])
  566. db.define_table('t1', Field('aa'))
  567. db.define_table('t2', Field('aa'), Field('b', db.t1))
  568. i1 = db.t1.insert(aa='1')
  569. i2 = db.t1.insert(aa='2')
  570. i3 = db.t1.insert(aa='3')
  571. db.t2.insert(aa='4', b=i1)
  572. db.t2.insert(aa='5', b=i2)
  573. db.t2.insert(aa='6', b=i2)
  574. db.t1._common_filter = lambda q: db.t1.aa>1
  575. self.assertEqual(db(db.t1).count(),2)
  576. self.assertEqual(db(db.t1).count(),2)
  577. q = db.t2.b==db.t1.id
  578. self.assertEqual(db(q).count(),2)
  579. self.assertEqual(db(q).count(),2)
  580. self.assertEqual(len(db(db.t1).select(left=db.t2.on(q))),3)
  581. db.t2._common_filter = lambda q: db.t2.aa<6
  582. self.assertEqual(db(q).count(),1)
  583. self.assertEqual(db(q).count(),1)
  584. self.assertEqual(len(db(db.t1).select(left=db.t2.on(q))),2)
  585. db.t2.drop()
  586. db.t1.drop()
  587. class TestImportExportFields(unittest.TestCase):
  588. def testRun(self):
  589. db = DAL(DEFAULT_URI, check_reserved=['all'])
  590. db.define_table('person', Field('name'))
  591. db.define_table('pet',Field('friend',db.person),Field('name'))
  592. for n in range(2):
  593. db(db.pet).delete()
  594. db(db.person).delete()
  595. for k in range(10):
  596. id = db.person.insert(name=str(k))
  597. db.pet.insert(friend=id,name=str(k))
  598. db.commit()
  599. stream = StringIO.StringIO()
  600. db.export_to_csv_file(stream)
  601. db(db.pet).delete()
  602. db(db.person).delete()
  603. stream = StringIO.StringIO(stream.getvalue())
  604. db.import_from_csv_file(stream)
  605. assert db(db.person.id==db.pet.friend)(db.person.name==db.pet.name).count()==10
  606. db.pet.drop()
  607. db.person.drop()
  608. db.commit()
  609. class TestImportExportUuidFields(unittest.TestCase):
  610. def testRun(self):
  611. db = DAL(DEFAULT_URI, check_reserved=['all'])
  612. db.define_table('person', Field('name'),Field('uuid'))
  613. db.define_table('pet',Field('friend',db.person),Field('name'))
  614. for n in range(2):
  615. db(db.pet).delete()
  616. db(db.person).delete()
  617. for k in range(10):
  618. id = db.person.insert(name=str(k),uuid=str(k))
  619. db.pet.insert(friend=id,name=str(k))
  620. db.commit()
  621. stream = StringIO.StringIO()
  622. db.export_to_csv_file(stream)
  623. stream = StringIO.StringIO(stream.getvalue())
  624. db.import_from_csv_file(stream)
  625. assert db(db.person).count()==10
  626. assert db(db.person.id==db.pet.friend)(db.person.name==db.pet.name).count()==20
  627. db.pet.drop()
  628. db.person.drop()
  629. db.commit()
  630. class TestDALDictImportExport(unittest.TestCase):
  631. def testRun(self):
  632. db = DAL(DEFAULT_URI, check_reserved=['all'])
  633. db.define_table('person', Field('name', default="Michael"),Field('uuid'))
  634. db.define_table('pet',Field('friend',db.person),Field('name'))
  635. dbdict = db.as_dict(flat=True, sanitize=False)
  636. assert isinstance(dbdict, dict)
  637. uri = dbdict["uri"]
  638. assert isinstance(uri, basestring) and uri
  639. assert len(dbdict["tables"]) == 2
  640. assert len(dbdict["tables"][0]["fields"]) == 3
  641. assert dbdict["tables"][0]["fields"][1]["type"] == db.person.name.type
  642. assert dbdict["tables"][0]["fields"][1]["default"] == db.person.name.default
  643. db2 = DAL(**dbdict)
  644. assert len(db.tables) == len(db2.tables)
  645. assert hasattr(db2, "pet") and isinstance(db2.pet, Table)
  646. assert hasattr(db2.pet, "friend") and isinstance(db2.pet.friend, Field)
  647. db.pet.drop()
  648. db.commit()
  649. db2.commit()
  650. have_serializers = True
  651. try:
  652. import serializers
  653. dbjson = db.as_json(sanitize=False)
  654. assert isinstance(dbjson, basestring) and len(dbjson) > 0
  655. unicode_keys = True
  656. if sys.version < "2.6.5":
  657. unicode_keys = False
  658. db3 = DAL(**serializers.loads_json(dbjson,
  659. unicode_keys=unicode_keys))
  660. assert hasattr(db3, "person") and hasattr(db3.person, "uuid") and\
  661. db3.person.uuid.type == db.person.uuid.type
  662. db3.person.drop()
  663. db3.commit()
  664. except ImportError:
  665. pass
  666. mpfc = "Monty Python's Flying Circus"
  667. dbdict4 = {"uri": DEFAULT_URI,
  668. "tables":[{"tablename": "tvshow",
  669. "fields": [{"fieldname": "name",
  670. "default":mpfc},
  671. {"fieldname": "rating",
  672. "type":"double"}]},
  673. {"tablename": "staff",
  674. "fields": [{"fieldname": "name",
  675. "default":"Michael"},
  676. {"fieldname": "food",
  677. "default":"Spam"},
  678. {"fieldname": "tvshow",
  679. "type": "reference tvshow"}]}]}
  680. db4 = DAL(**dbdict4)
  681. assert "staff" in db4.tables
  682. assert "name" in db4.staff
  683. assert db4.tvshow.rating.type == "double"
  684. assert (db4.tvshow.insert(), db4.tvshow.insert(name="Loriot"),
  685. db4.tvshow.insert(name="Il Mattatore")) == (1, 2, 3)
  686. assert db4(db4.tvshow).select().first().id == 1
  687. assert db4(db4.tvshow).select().first().name == mpfc
  688. db4.staff.drop()
  689. db4.tvshow.drop()
  690. db4.commit()
  691. dbdict5 = {"uri": DEFAULT_URI}
  692. db5 = DAL(**dbdict5)
  693. assert db5.tables in ([], None)
  694. assert not (str(db5) in ("", None))
  695. dbdict6 = {"uri": DEFAULT_URI,
  696. "tables":[{"tablename": "staff"},
  697. {"tablename": "tvshow",
  698. "fields": [{"fieldname": "name"},
  699. {"fieldname": "rating", "type":"double"}
  700. ]
  701. }]
  702. }
  703. db6 = DAL(**dbdict6)
  704. assert len(db6["staff"].fields) == 1
  705. assert "name" in db6["tvshow"].fields
  706. assert db6.staff.insert() is not None
  707. assert db6(db6.staff).select().first().id == 1
  708. db6.staff.drop()
  709. db6.tvshow.drop()
  710. db6.commit()
  711. class TestValidateAndInsert(unittest.TestCase):
  712. def testRun(self):
  713. import datetime
  714. from gluon.validators import IS_INT_IN_RANGE
  715. db = DAL(DEFAULT_URI, check_reserved=['all'])
  716. db.define_table('val_and_insert',
  717. Field('aa'),
  718. Field('bb', 'integer',
  719. requires=IS_INT_IN_RANGE(1,5))
  720. )
  721. rtn = db.val_and_insert.validate_and_insert(aa='test1', bb=2)
  722. self.assertEqual(rtn.id, 1)
  723. #errors should be empty
  724. self.assertEqual(len(rtn.errors.keys()), 0)
  725. #this insert won't pass
  726. rtn = db.val_and_insert.validate_and_insert(bb="a")
  727. #the returned id should be None
  728. self.assertEqual(rtn.id, None)
  729. #an error message should be in rtn.errors.bb
  730. self.assertNotEqual(rtn.errors.bb, None)
  731. #cleanup table
  732. db.val_and_insert.drop()
  733. class TestSelectAsDict(unittest.TestCase):
  734. def testSelect(self):
  735. db = DAL(DEFAULT_URI, check_reserved=['all'])
  736. db.define_table(
  737. 'a_table',
  738. Field('b_field'),
  739. Field('a_field'),
  740. )
  741. db.a_table.insert(a_field="aa1", b_field="bb1")
  742. rtn = db.executesql("SELECT id, b_field, a_field FROM a_table", as_dict=True)
  743. self.assertEqual(rtn[0]['b_field'], 'bb1')
  744. rtn = db.executesql("SELECT id, b_field, a_field FROM a_table", as_ordered_dict=True)
  745. self.assertEqual(rtn[0]['b_field'], 'bb1')
  746. self.assertEqual(rtn[0].keys(), ['id', 'b_field', 'a_field'])
  747. db.a_table.drop()
  748. class TestRNameTable(unittest.TestCase):
  749. #tests for highly experimental rname attribute
  750. def testSelect(self):
  751. db = DAL(DEFAULT_URI, check_reserved=['all'])
  752. rname = db._adapter.__class__.QUOTE_TEMPLATE % 'a very complicated tablename'
  753. db.define_table(
  754. 'easy_name',
  755. Field('a_field'),
  756. rname=rname
  757. )
  758. rtn = db.easy_name.insert(a_field='a')
  759. self.assertEqual(rtn.id, 1)
  760. rtn = db(db.easy_name.a_field == 'a').select()
  761. self.assertEqual(len(rtn), 1)
  762. self.assertEqual(rtn[0].id, 1)
  763. self.assertEqual(rtn[0].a_field, 'a')
  764. db.easy_name.insert(a_field='b')
  765. rtn = db(db.easy_name.id > 0).delete()
  766. self.assertEqual(rtn, 2)
  767. rtn = db(db.easy_name.id > 0).count()
  768. self.assertEqual(rtn, 0)
  769. db.easy_name.insert(a_field='a')
  770. db.easy_name.insert(a_field='b')
  771. rtn = db(db.easy_name.id > 0).count()
  772. self.assertEqual(rtn, 2)
  773. rtn = db(db.easy_name.a_field == 'a').update(a_field='c')
  774. rtn = db(db.easy_name.a_field == 'c').count()
  775. self.assertEqual(rtn, 1)
  776. rtn = db(db.easy_name.a_field != 'c').count()
  777. self.assertEqual(rtn, 1)
  778. avg = db.easy_name.id.avg()
  779. rtn = db(db.easy_name.id > 0).select(avg)
  780. self.assertEqual(rtn[0][avg], 3)
  781. rname = db._adapter.__class__.QUOTE_TEMPLATE % 'this is the person table'
  782. db.define_table(
  783. 'person',
  784. Field('name', default="Michael"),
  785. Field('uuid'),
  786. rname=rname
  787. )
  788. rname = db._adapter.__class__.QUOTE_TEMPLATE % 'this is the pet table'
  789. db.define_table(
  790. 'pet',
  791. Field('friend','reference person'),
  792. Field('name'),
  793. rname=rname
  794. )
  795. michael = db.person.insert() #default insert
  796. john = db.person.insert(name='John')
  797. luke = db.person.insert(name='Luke')
  798. #michael owns Phippo
  799. phippo = db.pet.insert(friend=michael, name="Phippo")
  800. #john owns Dunstin and Gertie
  801. dunstin = db.pet.insert(friend=john, name="Dunstin")
  802. gertie = db.pet.insert(friend=john, name="Gertie")
  803. rtn = db(db.person.id == db.pet.friend).select(orderby=db.person.id|db.pet.id)
  804. self.assertEqual(len(rtn), 3)
  805. self.assertEqual(rtn[0].person.id, michael)
  806. self.assertEqual(rtn[0].person.name, 'Michael')
  807. self.assertEqual(rtn[0].pet.id, phippo)
  808. self.assertEqual(rtn[0].pet.name, 'Phippo')
  809. self.assertEqual(rtn[1].person.id, john)
  810. self.assertEqual(rtn[1].person.name, 'John')
  811. self.assertEqual(rtn[1].pet.name, 'Dunstin')
  812. self.assertEqual(rtn[2].pet.name, 'Gertie')
  813. #fetch owners, eventually with pet
  814. #main point is retrieving Luke with no pets
  815. rtn = db(db.person.id > 0).select(
  816. orderby=db.person.id|db.pet.id,
  817. left=db.pet.on(db.person.id == db.pet.friend)
  818. )
  819. self.assertEqual(rtn[0].person.id, michael)
  820. self.assertEqual(rtn[0].person.name, 'Michael')
  821. self.assertEqual(rtn[0].pet.id, phippo)
  822. self.assertEqual(rtn[0].pet.name, 'Phippo')
  823. self.assertEqual(rtn[3].person.name, 'Luke')
  824. self.assertEqual(rtn[3].person.id, luke)
  825. self.assertEqual(rtn[3].pet.name, None)
  826. #lets test a subquery
  827. subq = db(db.pet.name == "Gertie")._select(db.pet.friend)
  828. rtn = db(db.person.id.belongs(subq)).select()
  829. self.assertEqual(rtn[0].id, 2)
  830. self.assertEqual(rtn[0]('person.name'), 'John')
  831. #as dict
  832. rtn = db(db.person.id > 0).select().as_dict()
  833. self.assertEqual(rtn[1]['name'], 'Michael')
  834. #as list
  835. rtn = db(db.person.id > 0).select().as_list()
  836. self.assertEqual(rtn[0]['name'], 'Michael')
  837. #isempty
  838. rtn = db(db.person.id > 0).isempty()
  839. self.assertEqual(rtn, False)
  840. #join argument
  841. rtn = db(db.person).select(orderby=db.person.id|db.pet.id,
  842. join=db.pet.on(db.person.id==db.pet.friend))
  843. self.assertEqual(len(rtn), 3)
  844. self.assertEqual(rtn[0].person.id, michael)
  845. self.assertEqual(rtn[0].person.name, 'Michael')
  846. self.assertEqual(rtn[0].pet.id, phippo)
  847. self.assertEqual(rtn[0].pet.name, 'Phippo')
  848. self.assertEqual(rtn[1].person.id, john)
  849. self.assertEqual(rtn[1].person.name, 'John')
  850. self.assertEqual(rtn[1].pet.name, 'Dunstin')
  851. self.assertEqual(rtn[2].pet.name, 'Gertie')
  852. #aliases
  853. if DEFAULT_URI.startswith('mssql'):
  854. #multiple cascade gotcha
  855. for key in ['reference','reference FK']:
  856. db._adapter.types[key]=db._adapter.types[key].replace(
  857. '%(on_delete_action)s','NO ACTION')
  858. rname = db._adapter.__class__.QUOTE_TEMPLATE % 'the cubs'
  859. db.define_table('pet_farm',
  860. Field('name'),
  861. Field('father','reference pet_farm'),
  862. Field('mother','reference pet_farm'),
  863. rname=rname
  864. )
  865. minali = db.pet_farm.insert(name='Minali')
  866. osbert = db.pet_farm.insert(name='Osbert')
  867. #they had a cub
  868. selina = db.pet_farm.insert(name='Selina', father=osbert, mother=minali)
  869. father = db.pet_farm.with_alias('father')
  870. mother = db.pet_farm.with_alias('mother')
  871. #fetch pets with relatives
  872. rtn = db().select(
  873. db.pet_farm.name, father.name, mother.name,
  874. left=[
  875. father.on(father.id == db.pet_farm.father),
  876. mother.on(mother.id == db.pet_farm.mother)
  877. ],
  878. orderby=db.pet_farm.id
  879. )
  880. self.assertEqual(len(rtn), 3)
  881. self.assertEqual(rtn[0].pet_farm.name, 'Minali')
  882. self.assertEqual(rtn[0].father.name, None)
  883. self.assertEqual(rtn[0].mother.name, None)
  884. self.assertEqual(rtn[1].pet_farm.name, 'Osbert')
  885. self.assertEqual(rtn[2].pet_farm.name, 'Selina')
  886. self.assertEqual(rtn[2].father.name, 'Osbert')
  887. self.assertEqual(rtn[2].mother.name, 'Minali')
  888. #clean up
  889. db.pet_farm.drop()
  890. db.pet.drop()
  891. db.person.drop()
  892. db.easy_name.drop()
  893. def testJoin(self):
  894. db = DAL(DEFAULT_URI, check_reserved=['all'])
  895. rname = db._adapter.__class__.QUOTE_TEMPLATE % 'this is table t1'
  896. rname2 = db._adapter.__class__.QUOTE_TEMPLATE % 'this is table t2'
  897. db.define_table('t1', Field('aa'), rname=rname)
  898. db.define_table('t2', Field('aa'), Field('b', db.t1), rname=rname2)
  899. i1 = db.t1.insert(aa='1')
  900. i2 = db.t1.insert(aa='2')
  901. i3 = db.t1.insert(aa='3')
  902. db.t2.insert(aa='4', b=i1)
  903. db.t2.insert(aa='5', b=i2)
  904. db.t2.insert(aa='6', b=i2)
  905. self.assertEqual(len(db(db.t1.id
  906. == db.t2.b).select(orderby=db.t1.aa
  907. | db.t2.aa)), 3)
  908. self.assertEqual(db(db.t1.id == db.t2.b).select(orderby=db.t1.aa
  909. | db.t2.aa)[2].t1.aa, '2')
  910. self.assertEqual(db(db.t1.id == db.t2.b).select(orderby=db.t1.aa
  911. | db.t2.aa)[2].t2.aa, '6')
  912. self.assertEqual(len(db().select(db.t1.ALL, db.t2.ALL,
  913. left=db.t2.on(db.t1.id == db.t2.b),
  914. orderby=db.t1.aa | db.t2.aa)), 4)
  915. self.assertEqual(db().select(db.t1.ALL, db.t2.ALL,
  916. left=db.t2.on(db.t1.id == db.t2.b),
  917. orderby=db.t1.aa | db.t2.aa)[2].t1.aa, '2')
  918. self.assertEqual(db().select(db.t1.ALL, db.t2.ALL,
  919. left=db.t2.on(db.t1.id == db.t2.b),
  920. orderby=db.t1.aa | db.t2.aa)[2].t2.aa, '6')
  921. self.assertEqual(db().select(db.t1.ALL, db.t2.ALL,
  922. left=db.t2.on(db.t1.id == db.t2.b),
  923. orderby=db.t1.aa | db.t2.aa)[3].t1.aa, '3')
  924. self.assertEqual(db().select(db.t1.ALL, db.t2.ALL,
  925. left=db.t2.on(db.t1.id == db.t2.b),
  926. orderby=db.t1.aa | db.t2.aa)[3].t2.aa, None)
  927. self.assertEqual(len(db().select(db.t1.aa, db.t2.id.count(),
  928. left=db.t2.on(db.t1.id == db.t2.b),
  929. orderby=db.t1.aa, groupby=db.t1.aa)),
  930. 3)
  931. self.assertEqual(db().select(db.t1.aa, db.t2.id.count(),
  932. left=db.t2.on(db.t1.id == db.t2.b),
  933. orderby=db.t1.aa,
  934. groupby=db.t1.aa)[0]._extra[db.t2.id.count()],
  935. 1)
  936. self.assertEqual(db().select(db.t1.aa, db.t2.id.count(),
  937. left=db.t2.on(db.t1.id == db.t2.b),
  938. orderby=db.t1.aa,
  939. groupby=db.t1.aa)[1]._extra[db.t2.id.count()],
  940. 2)
  941. self.assertEqual(db().select(db.t1.aa, db.t2.id.count(),
  942. left=db.t2.on(db.t1.id == db.t2.b),
  943. orderby=db.t1.aa,
  944. groupby=db.t1.aa)[2]._extra[db.t2.id.count()],
  945. 0)
  946. db.t2.drop()
  947. db.t1.drop()
  948. db.define_table('person',Field('name'), rname=rname)
  949. id = db.person.insert(name="max")
  950. self.assertEqual(id.name,'max')
  951. db.define_table('dog',Field('name'),Field('ownerperson','reference person'), rname=rname2)
  952. db.dog.insert(name='skipper',ownerperson=1)
  953. row = db(db.person.id==db.dog.ownerperson).select().first()
  954. self.assertEqual(row[db.person.name],'max')
  955. self.assertEqual(row['person.name'],'max')
  956. db.dog.drop()
  957. self.assertEqual(len(db.person._referenced_by),0)
  958. db.person.drop()
  959. class TestRNameFields(unittest.TestCase):
  960. # tests for highly experimental rname attribute
  961. def testSelect(self):
  962. db = DAL(DEFAULT_URI, check_reserved=['all'])
  963. rname = db._adapter.__class__.QUOTE_TEMPLATE % 'a very complicated fieldname'
  964. rname2 = db._adapter.__class__.QUOTE_TEMPLATE % 'rrating from 1 to 10'
  965. db.define_table(
  966. 'easy_name',
  967. Field('a_field', rname=rname),
  968. Field('rating', 'integer', rname=rname2, default=2)
  969. )
  970. rtn = db.easy_name.insert(a_field='a')
  971. self.assertEqual(rtn.id, 1)
  972. rtn = db(db.easy_name.a_field == 'a').select()
  973. self.assertEqual(len(rtn), 1)
  974. self.assertEqual(rtn[0].id, 1)
  975. self.assertEqual(rtn[0].a_field, 'a')
  976. db.easy_name.insert(a_field='b')
  977. rtn = db(db.easy_name.id > 0).delete()
  978. self.assertEqual(rtn, 2)
  979. rtn = db(db.easy_name.id > 0).count()
  980. self.assertEqual(rtn, 0)
  981. db.easy_name.insert(a_field='a')
  982. db.easy_name.insert(a_field='b')
  983. rtn = db(db.easy_name.id > 0).count()
  984. self.assertEqual(rtn, 2)
  985. rtn = db(db.easy_name.a_field == 'a').update(a_field='c')
  986. rtn = db(db.easy_name.a_field == 'c').count()
  987. self.assertEqual(rtn, 1)
  988. rtn = db(db.easy_name.a_field != 'c').count()
  989. self.assertEqual(rtn, 1)
  990. avg = db.easy_name.id.avg()
  991. rtn = db(db.easy_name.id > 0).select(avg)
  992. self.assertEqual(rtn[0][avg], 3)
  993. avg = db.easy_name.rating.avg()
  994. rtn = db(db.easy_name.id > 0).select(avg)
  995. self.assertEqual(rtn[0][avg], 2)
  996. rname = db._adapter.__class__.QUOTE_TEMPLATE % 'this is the person name'
  997. db.define_table(
  998. 'person',
  999. Field('name', default="Michael", rname=rname),
  1000. Field('uuid')
  1001. )
  1002. rname = db._adapter.__class__.QUOTE_TEMPLATE % 'this is the pet name'
  1003. db.define_table(
  1004. 'pet',
  1005. Field('friend','reference person'),
  1006. Field('name', rname=rname)
  1007. )
  1008. michael = db.person.insert() #default insert
  1009. john = db.person.insert(name='John')
  1010. luke = db.person.insert(name='Luke')
  1011. #michael owns Phippo
  1012. phippo = db.pet.insert(friend=michael, name="Phippo")
  1013. #john owns Dunstin and Gertie
  1014. dunstin = db.pet.insert(friend=john, name="Dunstin")
  1015. gertie = db.pet.insert(friend=john, name="Gertie")
  1016. rtn = db(db.person.id == db.pet.friend).select(orderby=db.person.id|db.pet.id)
  1017. self.assertEqual(len(rtn), 3)
  1018. self.assertEqual(rtn[0].person.id, michael)
  1019. self.assertEqual(rtn[0].person.name, 'Michael')
  1020. self.assertEqual(rtn[0].pet.id, phippo)
  1021. self.assertEqual(rtn[0].pet.name, 'Phippo')
  1022. self.assertEqual(rtn[1].person.id, john)
  1023. self.assertEqual(rtn[1].person.name, 'John')
  1024. self.assertEqual(rtn[1].pet.name, 'Dunstin')
  1025. self.assertEqual(rtn[2].pet.name, 'Gertie')
  1026. #fetch owners, eventually with pet
  1027. #main point is retrieving Luke with no pets
  1028. rtn = db(db.person.id > 0).select(
  1029. orderby=db.person.id|db.pet.id,
  1030. left=db.pet.on(db.person.id == db.pet.friend)
  1031. )
  1032. self.assertEqual(rtn[0].person.id, michael)
  1033. self.assertEqual(rtn[0].person.name, 'Michael')
  1034. self.assertEqual(rtn[0].pet.id, phippo)
  1035. self.assertEqual(rtn[0].pet.name, 'Phippo')
  1036. self.assertEqual(rtn[3].person.name, 'Luke')
  1037. self.assertEqual(rtn[3].person.id, luke)
  1038. self.assertEqual(rtn[3].pet.name, None)
  1039. #lets test a subquery
  1040. subq = db(db.pet.name == "Gertie")._select(db.pet.friend)
  1041. rtn = db(db.person.id.belongs(subq)).select()
  1042. self.assertEqual(rtn[0].id, 2)
  1043. self.assertEqual(rtn[0]('person.name'), 'John')
  1044. #as dict
  1045. rtn = db(db.person.id > 0).select().as_dict()
  1046. self.assertEqual(rtn[1]['name'], 'Michael')
  1047. #as list
  1048. rtn = db(db.person.id > 0).select().as_list()
  1049. self.assertEqual(rtn[0]['name'], 'Michael')
  1050. #isempty
  1051. rtn = db(db.person.id > 0).isempty()
  1052. self.assertEqual(rtn, False)
  1053. #join argument
  1054. rtn = db(db.person).select(orderby=db.person.id|db.pet.id,
  1055. join=db.pet.on(db.person.id==db.pet.friend))
  1056. self.assertEqual(len(rtn), 3)
  1057. self.assertEqual(rtn[0].person.id, michael)
  1058. self.assertEqual(rtn[0].person.name, 'Michael')
  1059. self.assertEqual(rtn[0].pet.id, phippo)
  1060. self.assertEqual(rtn[0].pet.name, 'Phippo')
  1061. self.assertEqual(rtn[1].person.id, john)
  1062. self.assertEqual(rtn[1].person.name, 'John')
  1063. self.assertEqual(rtn[1].pet.name, 'Dunstin')
  1064. self.assertEqual(rtn[2].pet.name, 'Gertie')
  1065. #aliases
  1066. rname = db._adapter.__class__.QUOTE_TEMPLATE % 'the cub name'
  1067. if DEFAULT_URI.startswith('mssql'):
  1068. #multiple cascade gotcha
  1069. for key in ['reference','reference FK']:
  1070. db._adapter.types[key]=db._adapter.types[key].replace(
  1071. '%(on_delete_action)s','NO ACTION')
  1072. db.define_table('pet_farm',
  1073. Field('name', rname=rname),
  1074. Field('father','reference pet_farm'),
  1075. Field('mother','reference pet_farm'),
  1076. )
  1077. minali = db.pet_farm.insert(name='Minali')
  1078. osbert = db.pet_farm.insert(name='Osbert')
  1079. #they had a cub
  1080. selina = db.pet_farm.insert(name='Selina', father=osbert, mother=minali)
  1081. father = db.pet_farm.with_alias('father')
  1082. mother = db.pet_farm.with_alias('mother')
  1083. #fetch pets with relatives
  1084. rtn = db().select(
  1085. db.pet_farm.name, father.name, mother.name,
  1086. left=[
  1087. father.on(father.id == db.pet_farm.father),
  1088. mother.on(mother.id == db.pet_farm.mother)
  1089. ],
  1090. orderby=db.pet_farm.id
  1091. )
  1092. self.assertEqual(len(rtn), 3)
  1093. self.assertEqual(rtn[0].pet_farm.name, 'Minali')
  1094. self.assertEqual(rtn[0].father.name, None)
  1095. self.assertEqual(rtn[0].mother.name, None)
  1096. self.assertEqual(rtn[1].pet_farm.name, 'Osbert')
  1097. self.assertEqual(rtn[2].pet_farm.name, 'Selina')
  1098. self.assertEqual(rtn[2].father.name, 'Osbert')
  1099. self.assertEqual(rtn[2].mother.name, 'Minali')
  1100. #clean up
  1101. db.pet_farm.drop()
  1102. db.pet.drop()
  1103. db.person.drop()
  1104. db.easy_name.drop()
  1105. def testRun(self):
  1106. db = DAL(DEFAULT_URI, check_reserved=['all'])
  1107. rname = db._adapter.__class__.QUOTE_TEMPLATE % 'a very complicated fieldname'
  1108. for ft in ['string', 'text', 'password', 'upload', 'blob']:
  1109. db.define_table('tt', Field('aa', ft, default='', rname=rname))
  1110. self.assertEqual(db.tt.insert(aa='x'), 1)
  1111. self.assertEqual(db().select(db.tt.aa)[0].aa, 'x')
  1112. db.tt.drop()
  1113. db.define_table('tt', Field('aa', 'integer', default=1, rname=rname))
  1114. self.assertEqual(db.tt.insert(aa=3), 1)
  1115. self.assertEqual(db().select(db.tt.aa)[0].aa, 3)
  1116. db.tt.drop()
  1117. db.define_table('tt', Field('aa', 'double', default=1, rname=rname))
  1118. self.assertEqual(db.tt.insert(aa=3.1), 1)
  1119. self.assertEqual(db().select(db.tt.aa)[0].aa, 3.1)
  1120. db.tt.drop()
  1121. db.define_table('tt', Field('aa', 'boolean', default=True, rname=rname))
  1122. self.assertEqual(db.tt.insert(aa=True), 1)
  1123. self.assertEqual(db().select(db.tt.aa)[0].aa, True)
  1124. db.tt.drop()
  1125. db.define_table('tt', Field('aa', 'json', default={}, rname=rname))
  1126. self.assertEqual(db.tt.insert(aa={}), 1)
  1127. self.assertEqual(db().select(db.tt.aa)[0].aa, {})
  1128. db.tt.drop()
  1129. db.define_table('tt', Field('aa', 'date',
  1130. default=datetime.date.today(), rname=rname))
  1131. t0 = datetime.date.today()
  1132. self.assertEqual(db.tt.insert(aa=t0), 1)
  1133. self.assertEqual(db().select(db.tt.aa)[0].aa, t0)
  1134. db.tt.drop()
  1135. db.define_table('tt', Field('aa', 'datetime',
  1136. default=datetime.datetime.today(), rname=rname))
  1137. t0 = datetime.datetime(
  1138. 1971,
  1139. 12,
  1140. 21,
  1141. 10,
  1142. 30,
  1143. 55,
  1144. 0,
  1145. )
  1146. self.assertEqual(db.tt.insert(aa=t0), 1)
  1147. self.assertEqual(db().select(db.tt.aa)[0].aa, t0)
  1148. ## Row APIs
  1149. row = db().select(db.tt.aa)[0]
  1150. self.assertEqual(db.tt[1].aa,t0)
  1151. self.assertEqual(db.tt['aa'],db.tt.aa)
  1152. self.assertEqual(db.tt(1).aa,t0)
  1153. self.assertTrue(db.tt(1,aa=None)==None)
  1154. self.assertFalse(db.tt(1,aa=t0)==None)
  1155. self.assertEqual(row.aa,t0)
  1156. self.assertEqual(row['aa'],t0)
  1157. self.assertEqual(row['tt.aa'],t0)
  1158. self.assertEqual(row('tt.aa'),t0)
  1159. ## Lazy and Virtual fields
  1160. db.tt.b = Field.Virtual(lambda row: row.tt.aa)
  1161. db.tt.c = Field.Lazy(lambda row: row.tt.aa)
  1162. row = db().select(db.tt.aa)[0]
  1163. self.assertEqual(row.b,t0)
  1164. self.assertEqual(row.c(),t0)
  1165. db.tt.drop()
  1166. db.define_table('tt', Field('aa', 'time', default='11:30', rname=rname))
  1167. t0 = datetime.time(10, 30, 55)
  1168. self.assertEqual(db.tt.insert(aa=t0), 1)
  1169. self.assertEqual(db().select(db.tt.aa)[0].aa, t0)
  1170. db.tt.drop()
  1171. def testInsert(self):
  1172. db = DAL(DEFAULT_URI, check_reserved=['all'])
  1173. rname = db._adapter.__class__.QUOTE_TEMPLATE % 'a very complicated fieldname'
  1174. db.define_table('tt', Field('aa', rname=rname))
  1175. self.assertEqual(db.tt.insert(aa='1'), 1)
  1176. self.assertEqual(db.tt.insert(aa='1'), 2)
  1177. self.assertEqual(db.tt.insert(aa='1'), 3)
  1178. self.assertEqual(db(db.tt.aa == '1').count(), 3)
  1179. self.assertEqual(db(db.tt.aa == '2').isempty(), True)
  1180. self.assertEqual(db(db.tt.aa == '1').update(aa='2'), 3)
  1181. self.assertEqual(db(db.tt.aa == '2').count(), 3)
  1182. self.assertEqual(db(db.tt.aa == '2').isempty(), False)
  1183. self.assertEqual(db(db.tt.aa == '2').delete(), 3)
  1184. self.assertEqual(db(db.tt.aa == '2').isempty(), True)
  1185. db.tt.drop()
  1186. def testJoin(self):
  1187. db = DAL(DEFAULT_URI, check_reserved=['all'])
  1188. rname = db._adapter.__class__.QUOTE_TEMPLATE % 'this is field aa'
  1189. rname2 = db._adapter.__class__.QUOTE_TEMPLATE % 'this is field b'
  1190. db.define_table('t1', Field('aa', rname=rname))
  1191. db.define_table('t2', Field('aa', rname=rname), Field('b', db.t1, rname=rname2))
  1192. i1 = db.t1.insert(aa='1')
  1193. i2 = db.t1.insert(aa='2')
  1194. i3 = db.t1.insert(aa='3')
  1195. db.t2.insert(aa='4', b=i1)
  1196. db.t2.insert(aa='5', b=i2)
  1197. db.t2.insert(aa='6', b=i2)
  1198. self.assertEqual(len(db(db.t1.id
  1199. == db.t2.b).select(orderby=db.t1.aa
  1200. | db.t2.aa)), 3)
  1201. self.assertEqual(db(db.t1.id == db.t2.b).select(orderby=db.t1.aa
  1202. | db.t2.aa)[2].t1.aa, '2')
  1203. self.assertEqual(db(db.t1.id == db.t2.b).select(orderby=db.t1.aa
  1204. | db.t2.aa)[2].t2.aa, '6')
  1205. self.assertEqual(len(db().select(db.t1.ALL, db.t2.ALL,
  1206. left=db.t2.on(db.t1.id == db.t2.b),
  1207. orderby=db.t1.aa | db.t2.aa)), 4)
  1208. self.assertEqual(db().select(db.t1.ALL, db.t2.ALL,
  1209. left=db.t2.on(db.t1.id == db.t2.b),
  1210. orderby=db.t1.aa | db.t2.aa)[2].t1.aa, '2')
  1211. self.assertEqual(db().select(db.t1.ALL, db.t2.ALL,
  1212. left=db.t2.on(db.t1.id == db.t2.b),
  1213. orderby=db.t1.aa | db.t2.aa)[2].t2.aa, '6')
  1214. self.assertEqual(db().select(db.t1.ALL, db.t2.ALL,
  1215. left=db.t2.on(db.t1.id == db.t2.b),
  1216. orderby=db.t1.aa | db.t2.aa)[3].t1.aa, '3')
  1217. self.assertEqual(db().select(db.t1.ALL, db.t2.ALL,
  1218. left=db.t2.on(db.t1.id == db.t2.b),
  1219. orderby=db.t1.aa | db.t2.aa)[3].t2.aa, None)
  1220. self.assertEqual(len(db().select(db.t1.aa, db.t2.id.count(),
  1221. left=db.t2.on(db.t1.id == db.t2.b),
  1222. orderby=db.t1.aa, groupby=db.t1.aa)),
  1223. 3)
  1224. self.assertEqual(db().select(db.t1.aa, db.t2.id.count(),
  1225. left=db.t2.on(db.t1.id == db.t2.b),
  1226. orderby=db.t1.aa,
  1227. groupby=db.t1.aa)[0]._extra[db.t2.id.count()],
  1228. 1)
  1229. self.assertEqual(db().select(db.t1.aa, db.t2.id.count(),
  1230. left=db.t2.on(db.t1.id == db.t2.b),
  1231. orderby=db.t1.aa,
  1232. groupby=db.t1.aa)[1]._extra[db.t2.id.count()],
  1233. 2)
  1234. self.assertEqual(db().select(db.t1.aa, db.t2.id.count(),
  1235. left=db.t2.on(db.t1.id == db.t2.b),
  1236. orderby=db.t1.aa,
  1237. groupby=db.t1.aa)[2]._extra[db.t2.id.count()],
  1238. 0)
  1239. db.t2.drop()
  1240. db.t1.drop()
  1241. db.define_table('person',Field('name', rname=rname))
  1242. id = db.person.insert(name="max")
  1243. self.assertEqual(id.name,'max')
  1244. db.define_table('dog',Field('name', rname=rname),Field('ownerperson','reference person', rname=rname2))
  1245. db.dog.insert(name='skipper',ownerperson=1)
  1246. row = db(db.person.id==db.dog.ownerperson).select().first()
  1247. self.assertEqual(row[db.person.name],'max')
  1248. self.assertEqual(row['person.name'],'max')
  1249. db.dog.drop()
  1250. self.assertEqual(len(db.person._referenced_by),0)
  1251. db.person.drop()
  1252. class TestQuoting(unittest.TestCase):
  1253. # tests for case sensitivity
  1254. def testCase(self):
  1255. db = DAL(DEFAULT_URI, check_reserved=['all'], ignore_field_case=False, entity_quoting=True)
  1256. if DEFAULT_URI.startswith('mssql'):
  1257. #multiple cascade gotcha
  1258. for key in ['reference','reference FK']:
  1259. db._adapter.types[key]=db._adapter.types[key].replace(
  1260. '%(on_delete_action)s','NO ACTION')
  1261. t0 = db.define_table('t0',
  1262. Field('f', 'string'))
  1263. t1 = db.define_table('b',
  1264. Field('B', t0),
  1265. Field('words', 'text'))
  1266. blather = 'blah blah and so'
  1267. t0[0] = {'f': 'content'}
  1268. t1[0] = {'B': int(t0[1]['id']),
  1269. 'words': blather}
  1270. r = db(db.t0.id==db.b.B).select()
  1271. self.assertEqual(r[0].b.words, blather)
  1272. t1.drop()
  1273. t0.drop()
  1274. # test field case
  1275. try:
  1276. t0 = db.define_table('table_is_a_test',
  1277. Field('a_a'),
  1278. Field('a_A'))
  1279. except Exception, e:
  1280. # some db does not support case sensitive field names mysql is one of them.
  1281. if DEFAULT_URI.startswith('mysql:') or DEFAULT_URI.startswith('sqlite:'):
  1282. db.rollback()
  1283. return
  1284. raise e
  1285. t0[0] = dict(a_a = 'a_a', a_A='a_A')
  1286. self.assertEqual(t0[1].a_a, 'a_a')
  1287. self.assertEqual(t0[1].a_A, 'a_A')
  1288. t0.drop()
  1289. def testPKFK(self):
  1290. # test primary keys
  1291. db = DAL(DEFAULT_URI, check_reserved=['all'], ignore_field_case=False)
  1292. if DEFAULT_URI.startswith('mssql'):
  1293. #multiple cascade gotcha
  1294. for key in ['reference','reference FK']:
  1295. db._adapter.types[key]=db._adapter.types[key].replace(
  1296. '%(on_delete_action)s','NO ACTION')
  1297. # test table without surrogate key. Length must is limited to
  1298. # 100 because of MySQL limitations: it cannot handle more than
  1299. # 767 bytes in unique keys.
  1300. t0 = db.define_table('t0', Field('Code', length=100), primarykey=['Code'])
  1301. t2 = db.define_table('t2', Field('f'), Field('t0_Code', 'reference t0'))
  1302. t3 = db.define_table('t3', Field('f', length=100), Field('t0_Code', t0.Code), primarykey=['f'])
  1303. t4 = db.define_table('t4', Field('f', length=100), Field('t0', t0), primarykey=['f'])
  1304. try:
  1305. t5 = db.define_table('t5', Field('f', length=100), Field('t0', 'reference no_table_wrong_reference'), primarykey=['f'])
  1306. except Exception, e:
  1307. self.assertTrue(isinstance(e, KeyError))
  1308. if DEFAULT_URI.startswith('mssql'):
  1309. #there's no drop cascade in mssql
  1310. t3.drop()
  1311. t4.drop()
  1312. t2.drop()
  1313. t0.drop()
  1314. else:
  1315. t0.drop('cascade')
  1316. t2.drop()
  1317. t3.drop()
  1318. t4.drop()
  1319. class TestTableAndFieldCase(unittest.TestCase):
  1320. """
  1321. at the Python level we should not allow db.C and db.c because of .table conflicts on windows
  1322. but it should be possible to map two different names into distinct tables "c" and "C" at the Python level
  1323. By default Python models names should be mapped into lower case table names and assume case insensitivity.
  1324. """
  1325. def testme(self):
  1326. return
  1327. class TestQuotesByDefault(unittest.TestCase):
  1328. """
  1329. all default tables names should be quoted unless an explicit mapping has been given for a table.
  1330. """
  1331. def testme(self):
  1332. return
  1333. if __name__ == '__main__':
  1334. unittest.main()
  1335. tearDownModule()