From b71aea969df20283f1e741f638f0278137146bf7 Mon Sep 17 00:00:00 2001 From: yumoqing Date: Tue, 16 Jul 2019 17:44:28 +0800 Subject: [PATCH] add crud --- sqlor/crud.py | 320 ++++++++++++++++++++++++++++++++++++++++++++++++ sqlor/filter.py | 106 ++++++++++++++++ 2 files changed, 426 insertions(+) create mode 100755 sqlor/crud.py create mode 100755 sqlor/filter.py diff --git a/sqlor/crud.py b/sqlor/crud.py new file mode 100755 index 0000000..a064535 --- /dev/null +++ b/sqlor/crud.py @@ -0,0 +1,320 @@ +# -*- coding:utf8 -*- +from .dbpools import DBPools +from .filter import DBFilter +from appPublic.objectAction import ObjectAction +from appPublic.dictObject import DictObject +from appPublic.timeUtils import date2str,time2str,str2Date +toStringFuncs={ + 'char':None, + 'str':None, + 'short':str, + 'long':str, + 'float':str, + 'date':date2str, + 'time':time2str, +} +fromStringFuncs={ + 'short':int, + 'long':int, + 'float':float, + 'date':str2Date, + 'time':str2Date +} + +class CRUD(object): + def __init__(self,dbname,tablename,rows=10): + self.pool = DBPools() + self.dbname = dbname + self.tablename = tablename + self.rows = rows + self.oa = ObjectAction() + + async def primaryKey(self): + data = await self.pool.getTablePrimaryKey(self.dbname,self.tablename) + return data + + async def forignKeys(self): + data = self.pool.getTableForignKeys(self.dbname,self.tablename) + return data + + async def I(self): + """ + fields information + """ + fields = await self.primaryKey() + pks = [ i.field_name for i in fields ] + data = await self.pool.getTableFields(self.dbname,self.tablename) + [ d.update({'primarykey':True}) for d in data if d.name in pks ] + data = self.oa.execute(self.dbname+'_'+self.tablename,'tableInfo',data) + return data + + async def fromStr(self,data): + fields = await getTableFields(self.dbname,self.tablename) + ret = {} + for k in data: + v = None if data[k] == '' else data[k] + for f in fields: + if k == f.name: + ret[k] = v + f = fromStringFuncs.get(f.type,None) + if f is not None and v is not None: + ret[k] = f(v) + return ret + + async def toStr(self,data): + fields = await getTableFields(self.dbname,self.tablename) + ret = {} + for k in data: + for f in fields: + if k == f.name: + ret[k] = data[k] + f = toStringFuncs.get(f.type,None) + if f is not None and data[k] is not None: + ret[k] = f(data[k]) + return ret + + async def datagrid(self,request,target): + fields = await self.I() + fs = [ self.defaultIOField(f) for f in fields ] + id = self.dbname+':'+ self.tablename + pk = await self.primaryKey() + idField = pk[0].field + data = { + "tmplname":"widget_js.tmpl", + "data":{ + "__ctmpl__":"datagrid", + "__target__":target, + "data":{ + "name":id, + "icon-conv":"icon-table", + "title":tablename, + "url":absurl('./RP.dspy?id=%s' % id), + "deleteUrl":absurl('./D.dspy?id=%s' % id), + "addUrl":absurl('./C.dspy?id=%s' % id), + "updateUrl":absurl('./U.dspy?id=%s' % id), + "idField":idField, + "dnd":True, + "view":"scrollview", + "fields":fs, + "toolbar":{ + "tools":[ + { + "name":"add", + "icon":"icon-add", + "label":"add ball" + }, + { + "name":"delete", + "icon":"icon-delete", + "label":"delete ball" + }, + { + "name":"moveup", + "icon":"icon-up", + "label":"moveup ball" + }, + { + "name":"movedown", + "icon":"icon-down", + "label":"movedown ball" + } + ] + }, + "options":{ + "pageSize":50, + "pagination":False + } + } + } + } + data = self.oa.execute(id,'datagrid',data) + return data + + def defaultIOField(self,f): + if f.type in ['str']: + return { + "primarykey":f.get('primarykey',False), + "name":f.name, + "hidden":False, + "sortable":True, + "label":f.title, + "align":"center", + "iotype":"text" + } + if f.type in ['float','short','long']: + return { + "primarykey":f.get('primarykey',False), + "sortable":True, + "name":f.name, + "hidden":False, + "label":f.title, + "align":"right", + "iotype":"text" + } + return { + "primarykey":f.get('primarykey',False), + "name":f.name, + "sortable":True, + "hidden":False, + "label":f.title, + "align":"center", + "iotype":"text" + } + + async def C(self,rec): + """ + create new data + """ + fields = await self.pool.getTableFields(self.dbname,self.tablename) + flist = [ f['name'] for f in fields ] + fns = ','.join(flist) + vfs = ','.join([ '${' + f + '}$' for f in flist ]) + data = {} + [ data.update({k.lower():v}) for k,v in rec.items() ] + @self.pool.runSQL + def addSQL(dbname,data): + sqldesc={ + "sql_string" : """ + insert into %s (%s) values (%s) + """ % (self.tablename,fns,vfs), + } + return sqldesc + + data = self.oa.execute(self.dbname+'_'+self.tablename,'beforeAdd',data) + await addSQL(self.dbname,data) + data = self.oa.execute(self.dbname+'_'+self.tablename,'afterAdd',data) + return data + + async def defaultFilter(self,NS): + fields = await self.pool.getTableFields(self.dbname,self.tablename) + d = [ '%s = ${%s}$' % (f.name,f.name) for f in fields if f.name in NS.keys() ] + if len(d) == 0: + return '' + ret = ' and ' + ' and '.join(d) + return ret + + def R(self,filters=None,NS={}): + """ + retrieve data + """ + @self.pool.runSQLIterator + def retrieve(dbname,data): + fstr = '' + if filters is not None: + fstr = ' and ' + dbf = DBFilter(filters) + fstr = fstr + dbf.genFilterString() + else: + fstr = self.defaultFilter(NS) + sqldesc = { + "sql_string":"""select * from %s where 1=1 %s""" % (self.tablename,fstr), + } + return sqldesc + + + data = self.oa.execute(self.dbname+'_'+self.tablename,'beforeRetieve',NS) + data = await retrieve(self.dbname,data,fstr) + data = self.oa.execute(self.dbname+'_'+self.tablename,'afterRetieve',data) + return data + + async def RP(self,filters=None,NS={}): + @self.pool.runPaging + def pagingdata(dbname,data,filterString): + fstr = "" + if filters is not None: + fstr = ' and ' + dbf = DBFilter(filters) + fstr = fstr + dbf.genFilterString() + else: + fstr = self.defaultFilter(NS) + + sqldesc = { + "sql_string":"""select * from %s where 1=1 %s""" % (self.tablename,filterString), + "default":{'rows':self.rows} + } + return sqldesc + + if not NS.get('sort',False): + fields = await self.pool.getTableFields(self.dbname,self.tablename) + NS['sort'] = fields[0]['name'] + d = await pagingdata(self.dbname,NS) + return d + + async def U(self,data): + """ + update data + """ + @self.pool.runSQL + def update(dbname,NS,condi,newData): + c = [ '%s = ${%s}$' % (i,i) for i in condi ] + u = [ '%s = ${%s}$' % (i,i) for i in newData ] + cs = ' and '.join(c) + us = ','.join(u) + sqldesc = { + "sql_string":"""update %s set %s where %s""" % (self.tablename,us,cs) + } + return sqldesc + + pk = await self.primaryKey() + pkfields = [k.field_name for k in pk ] + newData = [ k for k in data if k not in pkfields ] + data = self.oa.execute(self.dbname+'_'+self.tablename,'beforeUpdate',data) + await update(self.dbname,data,pkfields,newData) + data = self.oa.execute(self.dbname+'_'+self.tablename,'afterUpdate',data) + return data + + async def D(self,data): + """ + delete data + """ + @self.pool.runSQL + def delete(dbname,data,fields): + c = [ '%s = ${%s}$' % (i,i) for i in fields ] + cs = ' and '.join(c) + sqldesc = { + "sql_string":"delete from %s where %s" % (self.tablename,cs) + } + return sqldesc + + pk = await self.primaryKey() + pkfields = [k.field_name for k in pk ] + data = self.oa.execute(self.dbname+'_'+self.tablename,'beforeDelete',data) + await delete(self.dbname,data,pkfields) + data = self.oa.execute(self.dbname+'_'+self.tablename,'afterDelete',data) + return data + +if __name__ == '__main__': + DBPools({ + "ambi":{ + "driver":"pymssql", + "coding":"utf-8", + "dbname":"ambi", + "kwargs":{ + "user":"ymq", + "database":"ambi", + "password":"ymq123", + "host":"localhost" + } + }, + "metadb":{ + "driver":"pymssql", + "coding":"utf-8", + "dbname":"metadb", + "kwargs":{ + "user":"ymq", + "database":"metadb", + "password":"ymq123", + "host":"localhost" + } + } + }) + crud = CRUD('ambi') + #fields = crud.I('cashflow') + #for i in fields: + # print(i) + + data = crud.RP('cashflow') + print(data.total) + for i in data.rows: + print(i.balance,i.asid) + diff --git a/sqlor/filter.py b/sqlor/filter.py new file mode 100755 index 0000000..241c361 --- /dev/null +++ b/sqlor/filter.py @@ -0,0 +1,106 @@ +# -*- coding:utf8 -*- +""" +过滤器解释器 +解释json格式的SQL查询过滤 +过滤支持: +双目关系运算符: + AND + OR +单目关系运算符: + NOT +表达式: + 表达关系有:=,<>,>,<,>=,<=,in,not in + a=b格式的 +{ + "and":[ + { + "lv":{ + "tblabbr":"a1", + "field":"field1" + } + "op":"=", + "rv":{ + "type":"field", + "tblabbr":"table1" + "field":"field2" + } + }, + { + "or":[...] + } + { + "not":{...} + } + ] +} +""" +import ujson as json + +class DBFilter(object): + def __init__(self,filterjson): + self.filterjson = filterjson + + def save(self,fpath): + pass + + def getArguments(self): + pass + + def genFilterString(self): + ret = self._genFilterSQL(self.filterjson) + return ret + + def _genFilterSQL(self,fj): + keys = fj.keys() + if len(keys) == 1: + key = keys[0] + if key.lower() in ['and','or']: + if type(fj[key]) != type([]) or len(fj[key])<2: + raise Exception(key + ':' + json.dumps(fj[key]) + ':is not a array, or array length < 2') + a = ' %s ' % key + return a.join([self._genFilterSQL(f) for f in fj[key] ]) + if key.lower() == 'not': + if type(fj[key]) != type({}): + raise Exception(key + ':' + json.dumps(fj[key]) + ':is not a dict') + a = ' %s ' % key + return a + self._genFilterSQL(fj[key]) + return self._genFilterItems(fj) + + def _genFilterItems(self,fj): + keys = fj.keys() + assert 'lv' in keys + assert 'op' in keys + assert 'rv' in keys + op = fj['op'].lower() + assert op in ['=','<>','>','<','>=','<=','in','not in'] + return self._genFilterFieldValue(fj['lv']) + ' ' + fj['op'] + ' ' + self._genFilterRightValue(fj['rv']) + + def _genFilterFieldValue(self,fj): + keys = fj.keys() + assert 'field' in keys + ret = fj['field'] + if 'tblabbr' in keys: + ret = fj['tblabbr'] + '.' + ret + return ret + + def _genFilterRightValue(self,fj): + keys = fj.keys() + assert 'type' in keys + if fj['type'] == 'field': + return self._genFilterFieldValue(fj) + if fj['type'] == 'const': + return self._genFilterConstValue(fj) + if fj['type'] == 'parameter': + return self._getFilterParameterValue(fj) + + def _genFilterConstValue(self,fj): + keys = fj.keys() + assert 'value' in keys + return fj['value'] + + def _getFilterParameterValue(self,fj): + keys = fj.keys() + assert 'parameter' in keys + return fj['parameter'] + +