A simple database schema generator

这个是什么

标题翻译过来就是一个简单的数据库Schema生成器,源代码在Github上面传送门
你需要安装好Ruby,Graphviz,然后把代码clone下来就可以运行了。

这个的原理

Graphviz是一个根据特定语言的可视化软件,它可以根据dot文件里面描述的内容生成一张图片。
假设我有下面一段数据库的Schema

Club
==================================================
id                                         int(11)
name                                  varchar(255)
address                               varchar(255)
expired_at                                datetime
created_at                                datetime
updated_at                                datetime
ecard                                      int(11)
image_keys                            varchar(255)
portable                                tinyint(1)
--------------------------------------------------

School
==================================================
id                                         int(11)
name                                  varchar(255)
address                               varchar(255)
ecard                                      int(11)
expired_at                                datetime
created_at                                datetime
updated_at                                datetime
portable                                tinyint(1)
--------------------------------------------------

Game
==================================================
id                                         int(11)
start_at                                  datetime
end_at                                    datetime
lat                                         double
lng                                         double
address                               varchar(255)
created_at                                datetime
updated_at                                datetime
name                                  varchar(255)
image_key                             varchar(255)
image_keys                            varchar(255)
--------------------------------------------------

ClubGame
==================================================
game_id                                    int(11)
club_id                                    int(11)
--------------------------------------------------

SchoolGame
==================================================
game_id                                    int(11)
school_id                                  int(11)
--------------------------------------------------

ClubProfile
==================================================
id                                         int(11)
user_id                                    int(11)
club_id                                    int(11)
avatar_key                            varchar(255)
course_id                                  int(11)
gender                                     int(11)
birthday                                  datetime
point                                      int(11)
ce                                         int(11)
created_at                                datetime
updated_at                                datetime
realname                              varchar(255)
--------------------------------------------------

SchoolProfile
==================================================
id                                         int(11)
user_id                                    int(11)
avatar_key                            varchar(255)
classroom_id                               int(11)
gender                                     int(11)
birthday                                  datetime
point                                      int(11)
ce                                         int(11)
created_at                                datetime
updated_at                                datetime
realname                              varchar(255)
school_id                                  int(11)
--------------------------------------------------

好吧,其实上面的schema也是我生成出来的,因为之前Rails里面是有schema.rb的,所以我觉得我的Cubanana里面也要有一个schema.txt

所以当你有这样一个schema.txt的时候,你可以看到单独的表中所包含的字段,但是你也想看到表与表之间的联系,这个时候,其实最简单的就是foreign_key,Rails里面的convention over configuration思想其实让你在设计数据表的时候就考虑数据表之间的关联,虽然它没有真正的foreign_key这个东西,但你知道当另一个表(User)里面出现club_id的时候,你就知道这两个其实是有关联的。

所以你需要的是把schema.txt解析生成为schema.dot文件,一个简单的dot文件例如:

digraph G {
  rankdir=LR
  node [shape=box, color=blue]
  node1 [style=filled] 
  node2 [style=filled, fillcolor=red] 
  node0 -> node1 -> node2
}

对应了下图

G

简单来说一个图,包含了node(节点),edge(边),我这边为了偷懒,就用了无向图,也就是没有箭头的。

上面Schema中每一个Model其实就是一个节点,那么对应了下面的dot语言

ClubGame [label="ClubGame|{game_id|club_id|club_game_id}"];

边的描述更加简单

Game -> SchoolGame [dir="none"]

详细的你可以看Graphviz的文档,RTFD,:)

了解了原理,那么接下来就是解析文件,一通操作:

def split_into_nodes
    original = File.open(@source, 'r') { |file| file.readlines }
    blankless = original.reject{ |line| line.match(/^$/) }

    @nodes = blankless
      .join()
      .split("--------------------------------------------------").map do |b|
      sources = b.lines.reject{|line| line == "\n"}
      name = sources.first.gsub("\n",'')
      attrs = sources[2..-1].map { |e| e.split(' ')
      .join(':') }
      .reject{ |s| s.include? "created_at" }
      .reject{ |s| s.include? "updated_at"}
      .reject{ |s| s == "id:int(11)"}
      .concat ["#{name.underscore}_id:int(11)"]
      .uniq
      sn = SchemaNode.new(name, attrs)
    end
end

这么做是为了让你把上面Schema分解成单独的SchemaNode,那么现在节点有了,用to_structs方法就可以生成节点了,那么边呢?
所以其实就是,两点生成一条直线,唯一要做的就是你需要判断它们俩能不能连在一起,而连不连在一起就是说我一个表里面有没有另一个表的id,如下:

class Link
  def initialize(node_a, node_b)
    @node_a = node_a
    @node_b = node_b
  end

  def link?
    case_a = @node_b.attrs.include?("#{@node_a.name.underscore}_id:int(11)")
    case_b = @node_a.attrs.include?("#{@node_b.name.underscore}_id:int(11)")
    case_a || case_b
  end
end

哈哈哈,一开始遇到了一个问题,让我生成的图少了好几条线,百思不得其解,后来发现是因为比如ClubGame小写之后拼接的id是clubgame_id,而其实应该是club_game_id,Camel case 的锅,所以会有一个monkey patch:

class String
  def underscore
    self.gsub(/::/, '/').
    gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
    gsub(/([a-z\d])([A-Z])/,'\1_\2').
    tr("-", "_").
    downcase
  end
end

这个代替了downcase。

好的,非常棒,那么两个节点的操作完了,你生成的那么多节点呢???

那不就是两两组合吗,然后把连接着一起的数出来吗?鄙视写for循环的程序员,而且还是两层的。在数学上,这个是排列组合的问题,你们的数学都还给老师了吗???
所以Ruby的Array有一个方法叫做 combination 啊!其他语言也有,(尽管可能它也是for循环),重要的是,你写代码的时候,要知道它的数学原理。能简化你很多不必要的低级操作,避免你成为一个低级的程序员。

这个的演示

Example

最终的结果如图,我偷懒,不画箭头,但是箭头无非就是改变一下edge的判断条件。

May the source be with U, gays!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • pyspark.sql模块 模块上下文 Spark SQL和DataFrames的重要类: pyspark.sql...
    mpro阅读 13,147评论 0 13
  • 转载,觉得这篇写 SQLAlchemy Core,写得非常不错。不过后续他没写SQLAlchemy ORM... ...
    非梦nj阅读 10,825评论 1 14
  • 程序设计中常使用树型结构来表征某些数据的关联关系,如上下级、栏目结构、商品分类、菜单、回复等。 分类的层级关系可以...
    JunChow520阅读 9,520评论 4 3
  • 1.在苹果的应用商店下载Cisco 下载成功之后在手机桌面打开软件 打开软件点击链接,添加 填写说明和服务器地址,...
    62AbC49g阅读 13,646评论 0 0
  • 开篇第一句。 如果你是抱着完成写作梦想而阅读本文的鱼儿,那么遗憾的告诉你,这里,是一片靠文字吃饭的海洋。 本文所讲...
    星冠伯爵阅读 4,520评论 0 16