model.py 16 KB

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