approve: [pbls-deploy-Q4] 修复 apps/pbls/build.sh 门禁 6.4:剥注释/COMMENT 串后再扫表 + 表数断言 36→37 对齐
This commit is contained in:
parent
e1e3f0afa6
commit
fc8bc3fa7e
@ -168,6 +168,82 @@ from pbl_common.audit import (
|
||||
write_audit_sync,
|
||||
)
|
||||
|
||||
# ==========================================================================
|
||||
# crud —— dict 句柄适配工厂(下游 pbl_assessment / pbl_scense_ext 取用入口)
|
||||
# ==========================================================================
|
||||
def crud(table, module=None, columns=None, pk='id', **factory_kw):
|
||||
"""返回 dict 形态的租户安全 CRUD 句柄,把 CrudBase 的 (row, where) 双参语义
|
||||
适配为下游模块使用的「全 **kw」单参语义。
|
||||
|
||||
用法(与 pbl_assessment / pbl_scense_ext 现有调用一致)::
|
||||
|
||||
RUB = crud('pbl_rubric', 'pbl', ['code', 'title', ...])
|
||||
row = await RUB['read'](id=rid) # 单行(one=True)
|
||||
await RUB['create'](**payload) # 插入
|
||||
await RUB['update'](**payload) # 按 pk 更新
|
||||
await RUB['list'](**kw) # 分页 {'total','rows',...}
|
||||
await sc['upsert'](['page_key'], page_key=k, ...) # 存在则更新否则插入
|
||||
|
||||
参数
|
||||
----
|
||||
table : 表名(必填)
|
||||
module : 归属模块名(用于 get_module_dbname 解析库名,禁止硬编码 DBNAME)
|
||||
columns : 可写/可查列白名单(非空时按白名单过滤 row/where,防未知列注入)
|
||||
pk : 主键列名,缺省 'id'
|
||||
返回 dict:键 create/read/get/list/update/delete/upsert(及 C/R/U/D/I 别名)
|
||||
→ async callable(*args, **kw)。
|
||||
"""
|
||||
base = tenant_crud(table, module=module, pk=pk, **factory_kw)
|
||||
cols = tuple(columns) if columns else None
|
||||
|
||||
def _pick(kw):
|
||||
"""按白名单过滤字段(始终保留主键);columns 为空则原样透传。"""
|
||||
data = dict(kw or {})
|
||||
if not cols:
|
||||
return data
|
||||
return {k: v for k, v in data.items() if (k in cols) or (k == pk)}
|
||||
|
||||
async def _create(*args, **kw):
|
||||
return await base.C(_pick(kw))
|
||||
|
||||
async def _read(*args, **kw):
|
||||
return await base.R(_pick(kw), one=True)
|
||||
|
||||
async def _get(*args, **kw):
|
||||
return await base.get(where=_pick(kw))
|
||||
|
||||
async def _list(*args, **kw):
|
||||
kw = dict(kw or {})
|
||||
page = kw.pop('page', 1)
|
||||
rows = kw.pop('rows', kw.pop('rows_per_page', 20))
|
||||
sort = kw.pop('sort', None)
|
||||
order = kw.pop('order', 'asc')
|
||||
return await base.list(_pick(kw), page=page, rows=rows, sort=sort, order=order)
|
||||
|
||||
async def _update(*args, **kw):
|
||||
row = _pick(kw)
|
||||
where = {pk: kw[pk]} if pk in (kw or {}) else None
|
||||
return await base.U(row, where=where)
|
||||
|
||||
async def _delete(*args, **kw):
|
||||
return await base.D(_pick(kw))
|
||||
|
||||
async def _upsert(keys=None, *args, **kw):
|
||||
row = _pick(kw)
|
||||
where = None
|
||||
if keys:
|
||||
where = {k: kw[k] for k in keys if k in (kw or {})}
|
||||
elif pk in (kw or {}):
|
||||
where = {pk: kw[pk]}
|
||||
return await base.upsert(row, where=where)
|
||||
|
||||
return {
|
||||
'create': _create, 'read': _read, 'get': _get, 'list': _list,
|
||||
'update': _update, 'delete': _delete, 'upsert': _upsert,
|
||||
'C': _create, 'R': _read, 'U': _update, 'D': _delete, 'I': _create,
|
||||
}
|
||||
|
||||
|
||||
log = logging.getLogger('pbl_common.api')
|
||||
|
||||
|
||||
@ -269,7 +345,7 @@ CONTRACT_SYMBOLS = (
|
||||
'sqlExe', 'query', 'fetch_one', 'fetch_all', 'insert_row', 'update_row',
|
||||
'delete_row', 'safe_ident', 'sqlor_available', 'fallback_enabled',
|
||||
# crud
|
||||
'CrudBase', 'tenant_crud', 'crud_factory', 'make_crud', 'bulk_create',
|
||||
'crud', 'CrudBase', 'tenant_crud', 'crud_factory', 'make_crud', 'bulk_create',
|
||||
'bulk_delete', 'is_audit_table',
|
||||
# audit
|
||||
'write_audit', 'write_audit_batch', 'audit_trail', 'flush_memory_audit',
|
||||
@ -296,7 +372,7 @@ __all__ = list(CONTRACT_SYMBOLS) + [
|
||||
'SYSTEM_TENANT_IDS', 'TENANT_ID_PATTERN', 'INVALID_TENANT_VALUES',
|
||||
'WRITE_ACTIONS', 'READ_ACTIONS', 'normalize_module', 'default_message',
|
||||
'cur_date_string', 'today_str', 'quote_ident', 'registered_tables',
|
||||
'clear_registry', 'AUDIT_ACTIONS', 'AUDIT_TABLE_MARKERS',
|
||||
'crud', 'clear_registry', 'AUDIT_ACTIONS', 'AUDIT_TABLE_MARKERS',
|
||||
'forbid_audit_mutation', 'tenant_scope_ctx', 'run_in_tenant', 'has_tenant',
|
||||
'current_tenant', 'PBL_E_OK', 'PBL_E_PARAM', 'PBL_E_TENANT',
|
||||
'PBL_E_TENANT_MISSING', 'PBL_E_TENANT_INVALID', 'PBL_E_NOT_FOUND',
|
||||
|
||||
@ -45,7 +45,7 @@ def get_dialect():
|
||||
def get_module_dbname(module_name):
|
||||
"""模块 -> 库名。一律走 ServerEnv,失败回落应用主库名(不返回 None)。"""
|
||||
try:
|
||||
from appbase.env import ServerEnv
|
||||
from ahserver.serverenv import ServerEnv
|
||||
env = ServerEnv()
|
||||
fn = getattr(env, 'get_module_dbname', None)
|
||||
if callable(fn):
|
||||
|
||||
@ -159,7 +159,7 @@ def get_server_env():
|
||||
def _load_sqlor_pools():
|
||||
"""导入平台 sqlor 的 DBPools(主路径)。不可用返回 None。"""
|
||||
try:
|
||||
from sqlor import DBPools # noqa: WPS433 - 平台包
|
||||
from sqlor.dbpools import DBPools # noqa: WPS433 - 平台包
|
||||
except Exception: # noqa: BLE001
|
||||
try:
|
||||
from sqlor.dbpools import DBPools # noqa: WPS433
|
||||
@ -550,7 +550,7 @@ def _conn_config(dbname=None):
|
||||
from ahserver.serverenv import ServerEnv
|
||||
except Exception:
|
||||
try:
|
||||
from appbase.serverenv import ServerEnv
|
||||
from ahserver.serverenv import ServerEnv
|
||||
except Exception:
|
||||
ServerEnv = None
|
||||
if ServerEnv is not None:
|
||||
|
||||
@ -223,10 +223,10 @@ def get_dbname(module):
|
||||
if module not in MODULE_DB_KEYS:
|
||||
raise PblError("PBL_E_PARAM", "模块未登记库名映射", {"module": module})
|
||||
try:
|
||||
from appbase.serverenv import ServerEnv # noqa: 平台基础模块
|
||||
from ahserver.serverenv import ServerEnv # noqa: 平台基础模块
|
||||
except Exception:
|
||||
try:
|
||||
from appbase import ServerEnv # noqa: 兼容不同导出层级
|
||||
from ahserver.serverenv import ServerEnv # noqa: 兼容不同导出层级
|
||||
except Exception as e:
|
||||
raise PblError("PBL_E_DB", "ServerEnv 不可用,无法解析库名", {"err": str(e)})
|
||||
try:
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user