A simple database schema generat

作者: 布拿拿 | 来源:发表于2017-08-16 12:41 被阅读94次

这个是什么

标题翻译过来就是一个简单的数据库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!

相关文章

网友评论

本文标题:A simple database schema generat

本文链接:https://www.haomeiwen.com/subject/prcirxtx.html