model.py 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648
  1. # -*- coding: utf-8 -*-
  2. """
  3. demeter database
  4. name:__base__.py
  5. author:rabin
  6. """
  7. import os
  8. import uuid
  9. import short_url
  10. import json
  11. import traceback
  12. import re
  13. import math
  14. from demeter.core import *
  15. class Model(object):
  16. __table__ = ''
  17. __comment__ = ''
  18. def __init__(self, type, db, config):
  19. self.db = db
  20. self._type = type
  21. self._config = config
  22. self._table = self._config['prefix'] + '_' + self.__table__
  23. self._set = ''
  24. self._bind = {}
  25. self._attr = {}
  26. self._key = {}
  27. self.create()
  28. def cur(self):
  29. return self.db.cursor()
  30. def query(self, sql, method='select', fetch='fetchall'):
  31. cur = self.cur()
  32. bind = []
  33. if self._set:
  34. for key in self._set:
  35. self.check(key, self._set[key], self._attr[key])
  36. if self._set[key] == 'time':
  37. self._set[key] = self.time()
  38. elif self._set[key] == 'True':
  39. self._set[key] = True
  40. elif self._set[key] == 'False':
  41. self._set[key] = False
  42. elif 'date' in key and type(self._set[key]) != int:
  43. self._set[key] = self.mktime(self._set[key])
  44. elif self._attr[key].md5:
  45. self._set[key] = self.createMd5(self._set[key])
  46. bind.append(self._set[key])
  47. for value in self._key:
  48. if value[0] in self._bind and self._bind[value[0]] != None:
  49. val = self._bind[value[0]]
  50. if method == 'insert':
  51. self.check(value[0], val, self._attr[value[0]])
  52. self._attr[value[0]].unset()
  53. if type(val) == list and val:
  54. for i in val:
  55. bind.append(i)
  56. else:
  57. bind.append(val)
  58. if method == 'select' and ';' in sql:
  59. temp = sql.split(';')
  60. sql = temp[1]
  61. totalSql = temp[0]
  62. cur.execute(totalSql, bind)
  63. Demeter.config['page']['totalNum'] = self.fetch(cur, 'fetchone', 'count')
  64. Demeter.config['page']['total'] = int(math.ceil(round(float(Demeter.config['page']['totalNum'])/float(Demeter.config['page']['num']),2)))
  65. cur.execute(sql, bind)
  66. if method == 'select':
  67. return self.fetch(cur, fetch)
  68. id = True
  69. if method == 'insert':
  70. id = cur.fetchone()[0]
  71. self.db.commit()
  72. self._set = {}
  73. return id
  74. """
  75. try:
  76. except Exception, e:
  77. print e.message
  78. os._exit(0)
  79. """
  80. def fetch(self, cur, type, method = ''):
  81. load = getattr(cur, type)
  82. rows = load()
  83. desc = self._key
  84. desc = cur.description
  85. if type == 'fetchall':
  86. result = []
  87. if rows:
  88. for key in rows:
  89. row = {}
  90. i = 0
  91. for v in key:
  92. row[desc[i][0]] = v
  93. i = i + 1
  94. result.append(row)
  95. elif method == 'count':
  96. return rows[0]
  97. else:
  98. result = {}
  99. i = 0
  100. if rows:
  101. for key in rows:
  102. if not key:
  103. key = ''
  104. result[desc[i][0]] = key
  105. i = i + 1
  106. return result
  107. def attr(self, method):
  108. fields = vars(self.__class__)
  109. self._attr = {}
  110. self._bind = {}
  111. self._key = {}
  112. col = (int, str, long, float, unicode, bool, uuid.UUID)
  113. for field in fields:
  114. if isinstance(fields[field], Fields):
  115. self._attr[field] = fields[field]
  116. self._key[field] = self._attr[field].getKey()
  117. insert = (method == 'insert')
  118. update = (insert or method == 'update')
  119. if insert and self._attr[field].uuid:
  120. self.setUuid(field, col)
  121. bind = False
  122. val = self._attr[field].getArgv()
  123. if val or val == False:
  124. bind = True
  125. else:
  126. val = getattr(self, field)
  127. if isinstance(val, col):
  128. setattr(self, field, self._attr[field])
  129. bind = True
  130. elif insert and self._attr[field].default:
  131. val = self._attr[field].default
  132. bind = True
  133. if val == 'time':
  134. val = self.time()
  135. elif '.' in val:
  136. temp = val.split('.')
  137. val = Demeter.config[temp[0]][temp[1]]
  138. elif method == 'select' and self._attr[field].default and field == 'state':
  139. val = self._attr[field].default
  140. bind = True
  141. if bind and val != None:
  142. if type(val) == list:
  143. length = len(val)
  144. if length <= 1:
  145. val = val[0]
  146. if insert and self._attr[field].md5:
  147. val = self.createMd5(val)
  148. if self._attr[field].type == 'boolean' and isinstance(val, (str, unicode)):
  149. val = Demeter.bool(val)
  150. if type(val) == list:
  151. val = tuple(val)
  152. self._bind[field] = val
  153. self._attr[field].val(self._bind[field])
  154. self._attr[field].bind('%s')
  155. self._key = sorted(self._key.items(), key=lambda d:d[1], reverse = False)
  156. Counter().unset()
  157. def check(self, field, val, attr):
  158. if val == 'undefined':
  159. self.error(error)
  160. if attr.match == 'not':
  161. if not val:
  162. self.error(field + ' not exists')
  163. elif attr.match:
  164. if '|' in attr.match:
  165. temp = attr.match.split('|')
  166. match = temp[0]
  167. error = temp[1]
  168. else:
  169. match = attr.match
  170. error = field + ' not match:' + match
  171. if hasattr(Check, match):
  172. method = getattr(Check, match)
  173. result = method(val)
  174. else:
  175. result = re.search(match, val)
  176. if not result:
  177. self.error(error)
  178. def error(self, msg):
  179. for value in self._key:
  180. if value[0] in self._bind and self._bind[value[0]] != None:
  181. self._attr[value[0]].unset()
  182. self._set = {}
  183. Demeter.error(msg)
  184. def time(self):
  185. return Demeter.time()
  186. def mktime(self, value):
  187. return Demeter.mktime(value)
  188. def setUuid(self, field, col):
  189. id = getattr(self, self._attr[field].uuid)
  190. if isinstance(id, col):
  191. system = short_url.encode_url(id)
  192. else:
  193. system = self._attr[field].uuid
  194. name = system + '.' + self.__table__
  195. result = uuid.uuid5(uuid.uuid1(), name)
  196. result = str(result)
  197. setattr(self, field, result)
  198. def createMd5(self, value):
  199. return Demeter.md5(value, salt=True)
  200. def createState(self):
  201. if 'create' in self._config:
  202. create = Demeter.bool(self._config['create'])
  203. if create:
  204. return Demeter.runtime(self._type, self.__table__, json.dumps(self._key))
  205. return False
  206. def drop(self):
  207. return self.handle('drop')
  208. def create(self):
  209. return self.handle('create')
  210. def insert(self):
  211. return self.handle('insert')
  212. def update(self, *args, **kwargs):
  213. if args:
  214. self._set = args[0]
  215. else:
  216. self._set = kwargs
  217. return self.handle('update', set=self._set)
  218. def delete(self):
  219. return self.handle('delete')
  220. def select(self, type='fetchall',col = '*', order = 'cdate desc', group = '', limit = '0,100', page=False):
  221. pageConfig = {}
  222. if page and 'page' in Demeter.config:
  223. pageConfig['current'] = Demeter.config['page']['current']
  224. if page == True:
  225. pageConfig['num'] = 15
  226. elif 'num' in page:
  227. pageConfig['num'] = page['num']
  228. Demeter.config['page']['num'] = pageConfig['num']
  229. return self.handle('select', type=type, col=col, order=order, group=group, limit=limit, page=pageConfig)
  230. def manage(self):
  231. self.attr(method)
  232. return
  233. def handle(self, method='select', type='fetchall', col = '*', order = '', group = '', limit = '0,100', page=False, set = ''):
  234. self.attr(method)
  235. if method == 'create':
  236. create = self.createState()
  237. if create == False:
  238. return False
  239. if type == 'fetchone':
  240. limit = '0,1'
  241. load = getattr(Sql(self._type), method)
  242. return self.query(load(self._table, {'key':self._key, 'fields':self._attr, 'col':col, 'order':order, 'group':group, 'limit':limit, 'page':page, 'set':set, 'table_comment':self.__comment__}), method, type)
  243. class Fields(object):
  244. def __init__(self, type='', default='', primaryKey=False, autoIncrement=False, null=True, unique=False, check='', constraint='', comment='', uuid='', index=False, indexs=False, md5=False, match='', manage=''):
  245. self.type = type
  246. self.default = default
  247. self.primaryKey = primaryKey
  248. self.autoIncrement = autoIncrement
  249. self.null = null
  250. self.unique = unique
  251. self.check = check
  252. self.constraint = constraint
  253. self.comment = comment
  254. self.uuid = uuid
  255. self.index = index
  256. self.indexs = indexs
  257. self.md5 = md5
  258. self.key = Counter().inc()
  259. self.match = match
  260. self.value = ''
  261. self.argv = ''
  262. self.bindValue = ''
  263. self.expValue = '='
  264. self.logicValue = 'and'
  265. self.manage = manage
  266. def assgin(self, value, exp='=', logic='and'):
  267. self.add(value)
  268. self.exp(exp)
  269. self.logic(logic)
  270. return self
  271. def bind(self, value):
  272. self.bindValue = value
  273. return self
  274. def exp(self, value):
  275. """
  276. if type(self.expValue) != list:
  277. self.expValue = []
  278. self.expValue.append(value)
  279. """
  280. self.expValue = value
  281. return self
  282. def logic(self, value):
  283. """
  284. if type(self.logicValue) != list:
  285. self.logicValue = []
  286. self.logicValue.append(value)
  287. """
  288. self.logicValue = value
  289. return self
  290. def val(self, value, exp='=', logic='and'):
  291. if type(value) == list:
  292. length = len(value)
  293. if length <= 1:
  294. value = value[0]
  295. self.value = value
  296. if not self.expValue:
  297. self.exp(exp)
  298. if not self.logicValue:
  299. self.logic(logic)
  300. return self
  301. def getArgv(self):
  302. return self.argv
  303. def getVal(self):
  304. return self.value
  305. def getBind(self):
  306. return self.bindValue
  307. def getExp(self):
  308. if not self.expValue:
  309. return ''
  310. if type(self.expValue) == list:
  311. length = len(self.expValue)
  312. if length <= 1:
  313. result = self.expValue[0]
  314. else:
  315. result = self.expValue
  316. else:
  317. result = self.expValue
  318. return result
  319. def getKey(self):
  320. return self.key
  321. def getLogic(self):
  322. if not self.logicValue:
  323. return ''
  324. if type(self.logicValue) == list:
  325. length = len(self.logicValue)
  326. if length <= 1:
  327. result = self.logicValue[0]
  328. else:
  329. result = self.logicValue
  330. else:
  331. result = self.logicValue
  332. return result
  333. def unset(self):
  334. self.argv = None
  335. self.value = None
  336. self.bindValue = None
  337. self.expValue = '='
  338. self.logicValue = 'and'
  339. return self
  340. def add(self, value):
  341. """
  342. if not self.argv:
  343. self.argv = []
  344. self.argv.append(value)
  345. """
  346. self.argv = value
  347. return self
  348. def ins(self, value):
  349. self.argv = value
  350. self.exp('in')
  351. return self
  352. def nq(self, value):
  353. self.argv = value
  354. self.exp('!=')
  355. return self
  356. def like(self, value):
  357. self.argv = '%' + value + '%'
  358. self.exp('like')
  359. return self
  360. def mlike(self, value):
  361. self.argv = value
  362. self.exp('~')
  363. self.logic('and')
  364. return self
  365. def time(self, value):
  366. self.add(Demeter.mktime(value))
  367. return self
  368. def start(self, value):
  369. self.time(value)
  370. self.exp('>=')
  371. self.logic('and')
  372. return self
  373. def end(self, value):
  374. self.time(value)
  375. self.exp('<=')
  376. self.logic('and')
  377. return self
  378. class Counter(object):
  379. num = 0
  380. instance = None
  381. def __new__(cls, *args, **kwd):
  382. if Counter.instance is None:
  383. Counter.instance = object.__new__(cls, *args, **kwd)
  384. return Counter.instance
  385. def inc(self):
  386. self.num = self.num + 1
  387. return self.num
  388. def dec(self):
  389. self.num = self.num - 1
  390. return self.num
  391. def unset(self):
  392. self.num = 0
  393. return self.num
  394. class Sql(object):
  395. instance = None
  396. def __new__(cls, *args, **kwd):
  397. if Sql.instance is None:
  398. Sql.instance = object.__new__(cls, *args, **kwd)
  399. return Sql.instance
  400. def __init__(self, type):
  401. self.type = type
  402. def drop(self, table, args):
  403. sql = 'DROP TABLE IF EXISTS ' + table
  404. return sql
  405. def alter(self, table, args):
  406. sql = 'ALTER TABLE ' + table + ' ADD COLUMN '
  407. return sql
  408. def create(self, table, args):
  409. create = []
  410. primary = []
  411. unique = []
  412. indexs = []
  413. index = []
  414. comment = {}
  415. for value in args['key']:
  416. key = value[0]
  417. val = args['fields'][key]
  418. if val.primaryKey:
  419. primary.append(key)
  420. if val.unique:
  421. unique.append(key)
  422. if val.index:
  423. index.append((key, val.index))
  424. if val.indexs:
  425. indexs.append(key)
  426. fields = []
  427. fields.append(key)
  428. if val.autoIncrement and self.type == 'postgresql':
  429. fields.append('SERIAL')
  430. else:
  431. fields.append(val.type)
  432. if not val.null:
  433. fields.append('NOT NULL')
  434. if val.autoIncrement and self.type == 'mysql':
  435. fields.append('AUTO_INCREMENT')
  436. #约束
  437. if val.constraint:
  438. fields.append('CONSTRAINT ' + val.constraint)
  439. if val.check:
  440. fields.append('CHECK ' + val.check)
  441. if val.default:
  442. default = val.default
  443. if val.default == 'time':
  444. default = '0'
  445. if '.' in val.default:
  446. temp = val.default.split('.')
  447. default = Demeter.config[temp[0]][temp[1]]
  448. fields.append('DEFAULT \'' + str(default) + '\'')
  449. if val.comment:
  450. if self.type == 'mysql':
  451. fields.append('COMMENT \'' + val.comment + '\'')
  452. else:
  453. comment[key] = val.comment
  454. fields = ' '.join(fields)
  455. create.append(fields)
  456. if primary:
  457. create.append('PRIMARY KEY (' + ','.join(primary) + ')')
  458. if unique:
  459. create.append('UNIQUE (' + ','.join(unique) + ')')
  460. create = ','.join(create)
  461. sql = 'CREATE TABLE ' + table + '(' + create + ')'
  462. sql = self.drop(table, args) + ';' + sql
  463. if indexs:
  464. name = '_'.join(indexs)
  465. value = ','.join(indexs)
  466. sql = sql + ';' + 'CREATE INDEX ' + table + '_' + name +' ON ' + table + '(' + value + ')'
  467. if index:
  468. for value in index:
  469. sql = sql + ';' + 'CREATE INDEX ' + table + '_' + value[0] +' ON ' + table + value[1]
  470. if comment:
  471. if args['table_comment']:
  472. sql = sql + ';' + 'COMMENT ON TABLE ' + table + ' IS \''+args['table_comment']+'\''
  473. for key in comment:
  474. sql = sql + ';' + 'COMMENT ON COLUMN ' + table + '.'+key+' IS \''+comment[key]+'\''
  475. return sql
  476. def insert(self, table, args):
  477. fields = []
  478. values = []
  479. for value in args['key']:
  480. key = value[0]
  481. val = args['fields'][key].getBind()
  482. if val:
  483. values.append(val)
  484. fields.append(key)
  485. fields = ','.join(fields)
  486. values = ','.join(values)
  487. sql = 'INSERT INTO ' + table + ' (' + fields + ') VALUES (' + values + ')'
  488. if self.type == 'postgresql':
  489. sql = sql + ' RETURNING id'
  490. return sql
  491. def update(self, table, args):
  492. fields = []
  493. for key in args['set']:
  494. fields.append(key + ' = %s')
  495. fields = ','.join(fields)
  496. sql = 'UPDATE ' + table + ' SET ' + fields + self.where(args['key'], args['fields'])
  497. return sql
  498. def delete(self, table, args):
  499. sql = 'DELETE FROM ' + table + self.where(args['key'], args['fields'])
  500. return sql
  501. def select(self, table, args):
  502. string = ' FROM ' + table + self.where(args['key'], args['fields']) + ' ' + self.group(args['group'])
  503. sql = ''
  504. if args['page']:
  505. sql = 'SELECT count(1) as total' + string + ';'
  506. sql = sql + 'SELECT ' + args['col'] + string + ' ' + self.order(args['order']) + ' ' + self.limit(args['limit'], args['page'])
  507. return sql
  508. def where(self, key, fields):
  509. fields = self.fields(key, fields)
  510. if fields:
  511. return ' WHERE ' + fields
  512. return ''
  513. def fields(self, key, fields):
  514. result = ''
  515. k = 0
  516. for value in key:
  517. key = value[0]
  518. field = fields[key]
  519. bind = field.getBind()
  520. val = field.getVal()
  521. logic = field.getLogic()
  522. exp = field.getExp()
  523. if type(val) == list and val:
  524. n = 0
  525. for i in val:
  526. data = self.field(field, bind, key, k, logic[n], exp[n])
  527. n = n + 1
  528. if data:
  529. result = result + data
  530. k = 1
  531. else:
  532. data = self.field(field, bind, key, k, logic, exp)
  533. if data:
  534. result = result + data
  535. k = 1
  536. return result
  537. def field(self, field, val, key, k, logic, exp):
  538. result = ''
  539. if val:
  540. if k == 0:
  541. logic = ''
  542. else:
  543. logic = ' ' + logic
  544. result = logic + ' ' + key + ' ' + exp + ' ' + str(val)
  545. return result
  546. def order(self, value):
  547. result = ''
  548. if value:
  549. result = ' ORDER BY ' + value
  550. return result
  551. def group(self, value):
  552. result = ''
  553. if value:
  554. result = ' GROUP BY ' + value
  555. return result
  556. def limit(self, value, page):
  557. result = ''
  558. if page:
  559. value = str((int(page['current'])-1) * page['num']) + ',' + str(page['num'])
  560. if value:
  561. value = value.split(',')
  562. if self.type == 'mysql':
  563. result = ' LIMIT ' + value[0] + ',' + value[1]
  564. elif self.type == 'postgresql':
  565. result = ' LIMIT ' + value[1] + ' OFFSET ' + value[0]
  566. return result