From 92bdfb6acfd7a7ec074a8e025ce265dffc820795 Mon Sep 17 00:00:00 2001 From: canonical Date: Mon, 12 Aug 2024 20:18:57 +0800 Subject: [PATCH] =?UTF-8?q?=E5=85=81=E8=AE=B8=E5=BC=BA=E5=88=B6=E6=8C=87?= =?UTF-8?q?=E5=AE=9Acolumn=E7=9A=84class=E7=B1=BB=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/theory/nop-for-dsl.md | 32 +++++++++---------- .../java/io/nop/orm/model/OrmColumnModel.java | 11 +++++++ 2 files changed, 27 insertions(+), 16 deletions(-) diff --git a/docs/theory/nop-for-dsl.md b/docs/theory/nop-for-dsl.md index 2d9e5c2db..75319edf8 100644 --- a/docs/theory/nop-for-dsl.md +++ b/docs/theory/nop-for-dsl.md @@ -4,7 +4,7 @@ ## 一. 横向DSL分解: DSL特性向量空间 -图灵机能够实现图灵完备的根本原因在于图灵机可以被看作是一种虚拟机,它可以模拟所有其他的自动计算机器,而如果我们不断提升虚拟机的抽象层次,就会得到可以直接"运行"所谓领域特定语言(DSL)的虚拟机,但是因为DSL关注的重点是特定领域概念,它必然无法以最便利的方式表达所有通用计算逻辑(否则它就成为了通用语言),必然会导致某种信息溢出,成为所谓的Delta项。 +图灵机能够实现图灵完备的根本原因在于图灵机可以被看作是一种虚拟机,它可以模拟所有其他的自动计算机器,而如果我们不断提升虚拟机的抽象层次,就会得到可以直接"运行"所谓领域特定语言(DSL)的虚拟机,但是因为DSL关注的重点是特定领域概念,它必然无法以最便利的方式表达所有通用计算逻辑(否则它就成为了通用语言),必然会导致某种信息溢出,成为所谓的Delta项。 **在第一代、第二代、第三代程序语言的发展过程中,不断的提升抽象层次,但它们仍然都是通用程序语言,但是发展到第四代程序语言,我们很可能得到的不是另一种通用程序语言,而是大量领域特定语言所构成的DSL森林**,通过它们我们可以形成对原有程序结构的一种新的表示和认知。 @@ -25,35 +25,35 @@ App ~ [DSL1, DSL2, ..., Delta] 在日常开发中,我们经常可以发现一些逻辑结构之间存在相似性和某种**不精确的衍生关系**,例如后端数据模型与前端页面之间密切的关联,对于最简单的情况,我们可以根据数据模型直接推导得到它对应的增删改查页面,或者反向根据表单字段信息推导得到数据库存储结构。但是,这种不精确的衍生关系很难被现有的技术手段所捕获和利用,如果强行约定一些关联规则,则只能应用于非常受限的特定场景,而且还会导致与其他技术手段的不兼容性,难以复用已有的工具技术,也难以适应需求从简单到复杂的动态演化。 这正是**传统模型驱动架构所面临的两难抉择:模型要发挥最大作用就必须内置大量知识进行自动推理,但是内置的知识越多就越容易绑定在某个应用场景,难以处理预料之外的新需求**。 -Nop平台基于可逆计算理论为实现这种面向动态相似性的复用提供了标准的技术路线: +Nop平台基于可逆计算理论为实现这种面向动态相似性的复用提供了标准的技术路线: -1. 借助于嵌入式元编程和代码生成,**任意结构A和C之间都可以建立一条推理管线** +1. 借助于嵌入式元编程和代码生成,**任意结构A和C之间都可以建立一条推理管线** -2. **将推理管线分解为多个步骤 : A =\> B =\> C** +2. **将推理管线分解为多个步骤 : A =\> B =\> C** -3. **进一步将推理管线差量化**:A =\> `_B` =\> B =\> `_C` =\> C +3. **进一步将推理管线差量化**:A =\> `_B` =\> B =\> `_C` =\> C -4. **每一个环节都允许暂存和透传本步骤不需要使用的扩展信息** +4. **每一个环节都允许暂存和透传本步骤不需要使用的扩展信息** -具体来说,Nop内置的模型驱动生产线可以分解为四个主要模型: +具体来说,Nop内置的模型驱动生产线可以分解为四个主要模型: -1. XORM:面向存储层的领域模型 +1. XORM:面向存储层的领域模型 -2. XMeta:针对GraphQL接口层的领域模型,可以直接生成GraphQL的类型定义 +2. XMeta:针对GraphQL接口层的领域模型,可以直接生成GraphQL的类型定义 -3. XView:在业务层面理解的前端逻辑,采用表单、表格、按钮等少量UI元素,与前端框架无关 +3. XView:在业务层面理解的前端逻辑,采用表单、表格、按钮等少量UI元素,与前端框架无关 4. XPage:具体使用某种前端框架的页面模型 在模型推导的时候我们只是推导得到一个备选的结果(一般存放在以下划线为前缀的模型文件中),然后我们可以选择继承这个备选的模型,增加手工修正和依赖额外信息的Delta推理部分(存放在不以下划线为前缀的模型)。整个推理关系的各个步骤都是可选环节:**我们可以从任意步骤直接开始,也可以完全舍弃此前步骤所推理得到的所有信息**。例如我们可以手动增加`xview`模型,并不需要它一定具有特定的`xmeta`支持,也可以直接新建`page.yaml`文件,按照AMIS组件规范编写JSON代码,AMIS框架的能力完全不会受到推理管线的限制。借助于这种类似深度学习的深度分解模式,我们可以完全释放模型驱动的威力,同时在必要时可以通过Delta差量引入额外信息,最终成品的能力不会受到模型表达能力的限制。这也使得**我们建模时不需要再追求对各种细节需求的覆盖,只需要集中精力关注最核心、最普适的通用需求部分即可**。 > `XORM = Generator + Delta` -> +> > `XMeta = Generator + Delta` -> +> > `XView = Generator + Delta` -> -> `XPage = Generator + Delta` +> +> `XPage = Generator + Delta` ## 三. 非编程指的是非命令式编程 @@ -64,7 +64,7 @@ Nop是**Nop is nOt Programming**的递归缩写,Nop非编程指的是它不是 Nop平台没有使用Spring和Quarkus这种第三方框架,而是选择从零开始编写IoC/ORM/Workflow/BatchJob等一系列底层引擎,这里最重要的原因就是要根据可逆计算理论对这些引擎的设计进行改造。**每一个具有独立存在价值的引擎都必然对应于一个内在的模型,而这个模型也必然对应着一种DSL语言**。Nop平台的关键点是**为每一种引擎都明确定义出一个DSL,然后借助于Nop平台的基础设施,自动的实现DSL的解析、验证、缓存、分解合并、元编程等**。在这种情况下,所有的引擎都只需要处理自己特有的运行时逻辑即可,而且因为大量的可扩展设计都可以在编译期借助于Nop平台来完成,所以引擎的运行时结构可以得到极大的简化。在Nop平台中,每个引擎的代码量一般会比对应的开源实现要小一个数量级,同时还提供更丰富的功能、更好的可扩展性、更优异的性能。参见[Nop平台与SpringCloud的功能对比 ](https://mp.weixin.qq.com/s/Dra8yf2O5VMJyEPox4dGBw)。 -> Nop平台提供了大量底层引擎,可以对标SpringCloud生态的相应部分,它可以成为AI时代的一种类似SpringCloud的基础技术底座。 +> Nop平台的应用范围不仅仅是强调可视化编辑的低代码领域,它提供了大量底层引擎,可以对标SpringCloud生态的相应部分,有能力成为AI时代的一种类似SpringCloud的基础技术底座。 ## 四. 统一的元模型,统一的DSL结构构造规律 @@ -80,4 +80,4 @@ Nop平台没有使用Spring和Quarkus这种第三方框架,而是选择从零 但是,常见的内部DSL所存在的问题是,它们过于强调DSL语法与自然语言之间的表观相似性(实际上也不是与自然语言相似,只是与英语相似),实际上只是引入了不必要的形式复杂性。此外,一般内部DSL只是利用底层语言内置的类型系统来进行形式约束,往往并不能保证DSL语法的稳定性,完全可能存在多种等价的表达方式来表达同样的领域逻辑,所谓的DSL语法仅仅是一种不成文的约定而已。内部DSL的解析一般要依赖于底层语法的解析器,难以脱离于底层语言之外进行解析和转换,这也导致内部DSL的语法和语义与底层语言纠缠在一起,很少有人会关注内部DSL自身的概念完整性、可扩展性和结构可逆性。 -Nop平台的做法是引入统一的XDef元模型来规范化所有DSL的语法和语义结构,并提供了统一的开发和调试工具来辅助DSL的开发。只要掌握了元模型,就可以立刻掌握所有DSL的语法和分解合并、差量定制等标准方案,不需要针对每个DSL单独学习。使用Nop平台来开发一个新的引擎时,我们可以通过`xdef:ref`来引用已有的DSL,实现多个DSL的自然融合,通过XPL模板语言实现描述式向命令式的自动转换。具体参见[低代码平台中的元编程(Meta Programming)](https://mp.weixin.qq.com/s/LkTIVGSrK9zomPW4bNiqqA)。 \ No newline at end of file +Nop平台的做法是引入统一的XDef元模型来规范化所有DSL的语法和语义结构,并提供了统一的开发和调试工具来辅助DSL的开发。只要掌握了元模型,就可以立刻掌握所有DSL的语法和分解合并、差量定制等标准方案,不需要针对每个DSL单独学习。使用Nop平台来开发一个新的引擎时,我们可以通过`xdef:ref`来引用已有的DSL,实现多个DSL的自然融合,通过XPL模板语言实现描述式向命令式的自动转换。具体参见[低代码平台中的元编程(Meta Programming)](https://mp.weixin.qq.com/s/LkTIVGSrK9zomPW4bNiqqA)。 diff --git a/nop-orm-model/src/main/java/io/nop/orm/model/OrmColumnModel.java b/nop-orm-model/src/main/java/io/nop/orm/model/OrmColumnModel.java index ee1e3d645..27edde67f 100644 --- a/nop-orm-model/src/main/java/io/nop/orm/model/OrmColumnModel.java +++ b/nop-orm-model/src/main/java/io/nop/orm/model/OrmColumnModel.java @@ -18,6 +18,7 @@ public class OrmColumnModel extends _OrmColumnModel implements IColumnModel { private List columnRefs; private String sqlType; + private Class javaClass; public OrmColumnModel() { setInsertable(true); @@ -89,6 +90,16 @@ public void setColumnRefs(List columnRefs) { this.columnRefs = columnRefs; } + @Override + public Class getJavaClass() { + if (javaClass == null) + return getStdDataType().getJavaClass(); + return javaClass; + } + + public void setJavaClass(Class javaClass) { + this.javaClass = javaClass; + } public String getSqlType() { return sqlType;