我的github:codetoys,所有代码都将会位于ctfc库中。已经放入库中我会指出在库中的位置。
这些代码大部分以Linux为目标但部分代码是纯C++的,可以在任何平台上使用。
源码目录:CCTModel_UniversalDB
相关专题:自制代码生成器(嵌入式脚本语言)_初级代码游戏的博客-CSDN博客
基础:github源码指引:源码结构、编译、运行_github编译-CSDN博客
目录
一、代码结构
代码结构相当简单,一个头文件用来定义对象模型,一个cpp包含main函数并根据对象模型定义了一组对象,三个ct文件是代码模板,用来生成一组h和cpp文件。
二、编译、运行
rebuild.sh编译,run.sh运行。
三、输出
如果运行顺利结束,得到一组输出文件:
这里面没有cpp文件,因为我不喜欢修改makefile,喜欢把所有东西都放在头文件里。当然,代码模板输出什么内容、写到什么文件完全是代码控制的。
四、main函数
按照惯例,main函数没有很复杂的内容:
int main(int argc, char** argv)
{
if (!InitActiveApp("CCTModel_UniversalDB", 1024 * 1024, argc, argv))exit(1);
CCTModel_UniversalDB ctm;//模型对象
if (!Rooster_AddAllTable(&ctm))//定义模型,后面解释
{
thelog << "执行失败" << ende;
return __LINE__;
}
if (!ctm.CreateCode("ns_rooster_struct", "RoosterStruct", "."))//根据模板输出,后面解释
{
thelog << "执行失败" << ende;
return __LINE__;
}
thelog << "程序退出" << endi;
return 0;
}
关键就两步:
Rooster_AddAllTable(&ctm)创建了模型。
ctm.CreateCode("ns_rooster_struct", "RoosterStruct", ".")使用模型和代码模板输出代码。
五、创建模型
这是一个包含几张表的数据库设计,功能大概是一个定时任务控制系统。
代码如下:
bool Rooster_AddAllTable(CCTModel_UniversalDB* pCTM)
{
CCTModel_UniversalDB::table* p;
//资源类型,预定义的数值
p = pCTM->AddNewTable("RESOURCE_TYPE_D", "资源类型");
if (NULL == p)return false;
p->AddMember("RESOURCE_TYPE_ID", "long", "资源类型");
p->AddMember("COMMENT", "string", "备注");
p->SetPK("RESOURCE_TYPE_ID");
p->AddDML("InsertNewResourceType", "insert", "RESOURCE_TYPE_ID,COMMENT", "", "插入新资源类型");
//资源使用类型,预定义的数值
p = pCTM->AddNewTable("RESOURCE_USE_TYPE_D", "资源使用类型");
if (NULL == p)return false;
p->AddMember("RESOURCE_USE_TYPE_ID", "long", "资源使用类型ID");
p->AddMember("COMMENT", "string", "备注");
p->SetPK("RESOURCE_USE_TYPE_ID");
p->AddDML("InsertNewResourceUseType", "insert", "RESOURCE_USE_TYPE_ID,COMMENT", "", "插入新资源使用类型");
//资源
p = pCTM->AddNewTable("RESOURCE_D", "资源");
if (NULL == p)return false;
p->AddMember("RESOURCE_ID", "long", "资源ID");
p->AddMember("RESOURCE_NAME", "string", "资源名称");
p->AddMember("RESOURCE_TYPE_ID", "long", "资源类型");
p->AddMember("RESOURCE_WITH_SYS", "long", "资源是否区分sys/sys2");
p->AddMember("COMMENT", "string", "备注");
p->SetPK("RESOURCE_ID");
p->AddDML("InsertNewResource", "insert", "*", "", "插入新资源");
p->AddDML("GetAllResource", "select", "*", "", "获得全部");
//任务定义
p = pCTM->AddNewTable("TASK_D", "任务");
if (NULL == p)return false;
p->AddMember("TASK_ID", "long", "任务ID");
p->AddMember("TASK_NAME", "string", "任务名称");
p->AddMember("TASK_MULTIPLE", "long", "0非多开1多开");
p->AddMember("TASK_WITH_SYS", "long", "是否区分sys/sys2");
p->AddMember("TASK_PRIORITY", "long", "优先级,小的优先");
p->AddMember("TASK_PLAN_TIME", "string", "执行时间,‘2,8-16’,时间点或时间段");
p->AddMember("TASK_PLAN_INTERVAL", "long", "执行时间段的执行间隔(分钟0-59)");
p->AddMember("TASK_START_CMD", "string", "启动命令");
p->AddMember("COMMENT", "string", "备注");
p->SetPK("TASK_ID");
p->AddDML("InsertNewTaskDefine", "insert", "*", "", "插入新任务定义");
p->AddDML("GetAllTask", "select", "*", "", "获得全部");
//任务资源使用定义
p = pCTM->AddNewTable("TASK_RESOURCE_USE_D", "任务资源使用");
if (NULL == p)return false;
p->AddMember("TASK_ID", "long", "任务ID");
p->AddMember("RESOURCE_ID", "long", "资源ID");
p->AddMember("RESOURCE_USE_TYPE_ID", "long", "资源使用类型ID");
p->AddMember("COMMENT", "string", "备注");
p->SetPK("TASK_ID,RESOURCE_ID");
p->AddDML("InsertNewTaskResurceUseDefine", "insert", "TASK_ID,RESOURCE_ID,RESOURCE_USE_TYPE_ID,COMMENT", "", "插入新任务资源使用定义");
p->AddDML("GetAllTaskResourceUse", "select", "*", "", "获得全部");
//任务队列表
p = pCTM->AddNewTable("TASK_QUEUE", "待执行的任务队列");
if (NULL == p)return false;
p->AddMember("TASK_ID", "long", "任务ID");
p->AddMember("SYS", "long", "维度1");
p->AddMember("SYS2", "long", "维度2");
p->AddMember("TASK_NAME", "string", "任务名称(参考)");
p->AddMember("TASK_PRIORITY", "long", "优先级,小的优先(参考)");
p->AddMember("COMMENT", "string", "备注(参考)");
p->AddMember("INSERT_TIME", "time", "开始时间", "", "TIME_LOG");
p->SetPK("TASK_ID,SYS,SYS2");
p->AddDML("InsertNewTaskQueue", "insert", "TASK_ID,SYS,SYS2,TASK_NAME,TASK_PRIORITY,COMMENT,INSERT_TIME", "", "插入新任务队列");
p->AddDML("DeleteTaskQueue", "delete", "", "TASK_ID,SYS,SYS2", "删除任务队列");
p->AddDML("GetAllTaskQueue", "select", "*", "", "获取全部任务队列");
p->AddDML("GetTaskQueue", "select", "*", "TASK_ID,SYS,SYS2", "获取任务队列");
//任务执行表
p = pCTM->AddNewTable("TASK_LOG", "任务日志");
if (NULL == p)return false;
p->AddMember("TASK_LOG_ID", "long", "任务执行序列号SEQ_TASK_LOG");
p->AddMember("TASK_ID", "long", "任务ID");
p->AddMember("SYS", "long", "维度1");
p->AddMember("SYS2", "long", "维度2");
p->AddMember("PID", "long", "任务所在的进程,客户方写入");
p->AddMember("START_TIME", "time", "开始时间", "", "TIME_LOG");
p->AddMember("FINISH_TIME", "time", "结束时间", "", "TIME_LOG");
p->AddMember("RETURN_VALUE", "long", "返回值 0成功 <0Rooster错误 >0任务错误");
p->AddMember("UPDATE_TIME", "time", "记录更新时间", "", "TIME_LOG");
p->SetPK("TASK_LOG_ID");
p->AddDML("InsertNewTaskLog", "insert", "TASK_LOG_ID,TASK_ID,SYS,SYS2,START_TIME,UPDATE_TIME", "", "插入新任务日志");
p->AddDML("UpdateTaskLog", "update", "PID,UPDATE_TIME", "TASK_LOG_ID", "更新任务日志", "finish_time=0");
p->AddDML("FinishTaskLog", "update", "FINISH_TIME,RETURN_VALUE,UPDATE_TIME", "TASK_LOG_ID", "更新任务日志", "finish_time=0");
p->AddDML("GetCurrentTask", "select", "*", "", "获取正在运行的任务", "finish_time=0");
//序列
if (NULL == pCTM->AddNewSequence("SEQ_TASK_LOG", "TASK日志序列", 0))return false;
return true;
}
具体这个模型做什么不重要,重要的是如何清晰明了地定义了表、列、主键、DML操作和序列,这种定义方式与具体实现无关(不同数据库的SQL语法是不同的),与实现相关的复杂性在模板文件中解决。这种定义方式也隐藏了具体SQL的繁琐细节,仅仅保留了关键要素,具体细节同样在模板文件中解决。
整个体系的另一部分复杂度由模型的实现解决。模型的实现是C++代码,可以在代码里预先处理不同的数据类型在不同场景下应该输出什么样的代码。当然理论上所有这一切都可以在代码模板中解决,但实际复杂度非常不同。
六、模型
模型由CCTModel_UniversalDB.h文件定义,完整内容直接看github上的文件,总体是这个样子:
逐级定义了所有对象的属性,并做了一些处理,代码模板根据这些对象属性来输出代码。
七、代码模板
三个ct文件是代码模板,根据DML定义生成SQL的函数的代码模板如下:
<%if S.type equal "update"%>
//构造SQL语句 ${S} ${S.comment}
string & sql${S}(<%foreach M in S.where_members%> ${M.ParamType} __${M.ParamName} ,<%endforeach%>
<%foreach M in S.op_members%> ${M.ParamType} _${M.ParamName} ,<%endforeach%> string & sql)
{
char buf[2048];
string fmr = (string)"update ${table} set <%foreach M in S.op_members ,%>${M.GetName}='${M.PrintfType}'<%endforeach%> "
<%if S.hasWhere exist%>
" where "
<%if S.where_members exist%>
" <%foreach M in S.where_members and%> ${M}='${M.PrintfType}' <%endforeach%>"
<%endif%>
<%if S.other_where exist%>
<%if S.where_members exist%>" and "<%endif%>"${S.other_where}"
<%endif%>
<%endif%>
;
sprintf(buf, fmr.c_str()
<%foreach M in S.op_members%>, _${M}<%endforeach%>
<%if S.where_members exist%>
<%foreach M in S.where_members%>, __${M} <%endforeach%>
<%endif%>
);
return sql = buf;
}
充满了foreach处理。相当复杂。
(这里是文档结束)