From 41e03aac4662eb1c9782686f99f73121fbf4932a Mon Sep 17 00:00:00 2001 From: yumoqing Date: Tue, 7 Jan 2025 12:11:29 +0800 Subject: [PATCH] bugfix --- README.md | 152 +++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 140 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index c0c551f..d13992e 100755 --- a/README.md +++ b/README.md @@ -251,11 +251,35 @@ when ahserver running behind the nginx, nginx should be forward following header * X-Forwarded-Scheme: scheme in client browser * X-Forwarded-Host: host in client browser * X-Forwarded-Url: url in client browser +* X-Forwarded-Prepath: subfolder name if if ahserver is behind nginx and use subfolder proxy. ## environment for processors When coding in processors, ahserver provide some environment stuff for build apllication, there are modules, functions, classes and variables +### session environment + +* async get_user() +a coroutine to get userid if user not login, it return None +* async remember_user(userid, username='', userorgid='') +a coroutine to set session user info: userid, name, orgid +* async forget_user() +a coroutine to forget session user information, and get_user() will return None +* async redirect(url) +a coroutine to redirect request to a new url +* entire_url(url) +a function to convert url to a url with http(s)://servername:port/repath/.... format, a outside url will return argument's url without change. +* aiohttp_client +aiohttp_client is aiohttp.client class to make a new request to other server +* gethost() +a function to get client ip +* async path_call(path, **kw) +a coroutine to call other source in server with path +* params_kw +dictionary to storages data tranafers from client. if files upload from client, upload file stored under the folder defined in configure file named by "files", the params_kw only storage the subpath under "files" defined folder. + +### global environment + ### modules: * time @@ -264,18 +288,122 @@ When coding in processors, ahserver provide some environment stuff for build apl * json ### functions: -* configValue -* isNone -* int -* str -* float -* type -* str2date -* str2datetime -* curDatetime -* uuid -* runSQL -* runSQLPaging +* configValue(k): +function return configuration file value in k, k is start with '.', examples: configValue('.website') will return website value in configuration file; configValue('.website.port') will return port under website in configuration file. + +* isNone(v) +a function check v is or not None, if is return True, else return False +* int(v) +a function to convert v to integer +* str(v) +a function to convert v to string +* float(v) +a function to convert v to float +* type(v) +a function to get v's type +* str2date(dstr) +a function to convert string with "YYYY-MM-DD" format to datetime.datetime instance +* str2datetime(dstr) +a function to convert string with "YYYY-MM-DD" format to datetime.datetime instance +* curDatetime() +a function to get current date and time in datetime.datetime instsance +* uuid() +a function to get a uuid value +* DBPools() +a function to get a db connection from sqlor connection pool, further infor see [sqlor](https://git.kaiyuancloud.cn/yumoqing/sqlor) + +all the databases it can connected to need to defiend in 'databases' in configuration file. + +CRUD use case: + +by use CRUD, the table must have a id field as primay key. + +CRUD use case 1(insert data to table. in a insert.dspy file) +``` +db = DBPools() +async with db.sqlorContext('dbname1') as sor: + ns = { + 'id':uuid(), + 'field1':1 + } + recs = await sor.C('tbl1', ns) +``` + +CRUD use case 2(update data in table. in a update.dspy file) +``` +ns = params_kw.copy() # get data from client +db = DBPools() +async with db.sqlorContext('dbname1') as sor: + await sor.U('tbl1', ns) +``` +CRUD use case 3(delete data in table. in a delete.dspy file) +``` +ns = { + 'id':params_kw.id +} +db = DBPools() +async with db.sqlorContext('dbname1') as sor: + await sor.D('tbl1', ns) +``` +CRUD use case 4(query date from table, in a search.dspy file) +``` +ns = params_kw.copy() +db = DBPools() +async with db.sqlorContext('dbname1') as sor: + recs = await sor.R('tbl1', ns) + # recs is d list with element is a DictObject instance with all the table fields data + return recs +``` +CRUD use case 5(paging query data from table, in a search_paging.dspy file) +``` +ns = params_kw.copy() +if ns.get('page') is None: + ns['page'] = 1 +if ns.get('sort') is None: + ns['sort'] = 'id desc' +db = DBPools() +async with db.sqlorContext('dbname1') as sor: + recs = await sor.RP('tbl1', ns) + # recs is a DictObject instance with two keys: "total": result records, "rows" return data list + # example: + # { + # "total":423123, + # "rows":[ ..... ] max record is "pagerows" in ns, default is 80 + # } + return recs +``` + +SQL EXECUTE use case 1 +``` +sql = "..... where id=${id}$ and field1 = ${var1}$ ..." +db = DBPools() +async with db.sqlorContext('dbname') as sor: + r = await sor.sqlExe(sql, {'id':'iejkuiew', 'var1':1111}) + # if sql is a select command, r is a list with data returned, is a instance of DictObject + .... +``` + +SQL EXECUTE use case 2 +``` +sql = "..... where id=${id}$ and field1 = ${var1}$ ..." +db = DBPools() +async with db.sqlorContext('dbname') as sor: + r = await sor.sqlPaging(sql, {'id':'iejkuiew', + 'page':1, + 'pagerows':60, + 'sort':'field1', + 'var1':1111}) + # r is a DictObject instance with two keys: "total": result records, "rows" return data list + # example: + # { + # "total":423123, + # "rows":[ ..... ] max record is "pagerows" in ns, default is 80 + # } + .... +``` + + + * runSQLIterator * runSQLResultFields * getTables