· 7 years ago · Oct 03, 2018, 09:14 AM
1# Sequel Basic Scafolding Model Generator for MySQL
2# This routine takes all the table of a database, en generates all Sequel models for Ramaze
3# For each table model we put :
4# - A header that reminds you the table structure
5# - the plugin list you wrote in 'plugin_to_add' array
6# - The Sequel referential inegrity : one_to_many, many_to_one
7# - A "Validate" method that checks not nullable columnns and unique columns
8# - Generates init.rb to be include in the project
9#
10# Note : db_connect.rb should already exists. Create it using Rake
11# WARNING !
12# This script is a very very very partial implementation of Sequel features
13# It is only usefull at the beginning of a project to create all Sequel models of a database.
14#
15
16require 'sequel'
17
18require_relative '../model/db_connect'
19
20# Target dir
21@model_dir_target = "../model"
22
23# List of plugins to add to the model
24plugin_to_add = [
25 "validation_helpers",
26 "json_serializer"
27]
28
29# International Error message
30message_empty = "ne peut pas être vide" # "cannot be empty"
31
32# List of the tables we want to create scafolding Sequel model
33models_to_create = DB.tables
34
35############### Do not modify below ################
36
37# Creating file and retreving a file pointer
38def createfile(name)
39 filename = File.join(@model_dir_target, name)
40 if !File.exists?(filename)
41 puts "creating #{filename}"
42 File.new(filename, "w")
43 else
44 puts "#{filename} already exists."
45 end
46end
47
48# Writing a nice header in files
49def writeheader(f, title)
50 f.puts "#coding: utf-8"
51 f.puts "#"
52 f.puts "# #{title}"
53 f.puts "# generated #{Time.now.to_s} by #{$0}"
54 f.puts "#"
55end
56
57# Write an association between two Models and manage special keys
58def write_association(f, association_type, table_name, foreign_key)
59 f.write(" #{association_type} :#{table_name}")
60 # Specify column name if it is composite
61 columns = foreign_key[:columns]
62 if columns.length > 1
63 f.write(", :key=>#{columns}")
64 else
65 # or if it does not respect the convention
66 unless columns[0].to_s == "#{foreign_key[:table]}_id"
67 f.write(", :key=>:#{columns[0]}")
68 end
69 end
70 f.write("\n")
71end
72
73############### Main ################
74models_to_create.each do |m|
75 # Camelize table_name to create a ClassName
76 modelName = m.to_s.split(/[^a-z0-9]/i).map{|w| w.capitalize}.join
77 # model creation if it does not exists
78 model = createfile(m.to_s + ".rb")
79 next if model.nil?
80
81 writeheader(model, "model for '#{m}' table")
82
83 # HEADER : Table definition
84 line = "# " << "-" * 30 << "+" << "-" * 21 << "+" << "-" * 10 << "+" << "-" * 10 << "+" << "-" * 12 << "+" << "-" * 20
85 model.puts(line)
86 model.puts("# COLUMN_NAME" << " " * 19 << "| DATA_TYPE" << " " * 11 << "| NULL? | KEY | DEFAULT | EXTRA")
87 model.puts(line)
88 DB.schema(m).each do |c|
89 col = c[1]
90 tab = 30 - c[0].to_s.size
91 data_type = col[:db_type].to_s
92 tab2 = 20 - data_type.size
93 allow_null = col[:allow_null].to_s
94 tab3 = 9 - allow_null.size
95 column_key = ""
96 if col[:primary_key]
97 column_key = "PRI"
98 else
99 DB.indexes(m).each do |name, info|
100 column_key = info[:unique] ? "UNI" : "MUL" if info[:columns].include?(c[0])
101 end
102 end
103 tab4 = 9 - column_key.size
104 default = col[:default].to_s
105 tab5 = 11 - default.size
106 extra = col[:auto_increment] ? "auto_increment" : ""
107 model.puts("# #{c[0]}#{' '*tab}| #{data_type}#{' '*tab2}| #{allow_null}#{' '*tab3}| #{column_key}#{' '*tab4}| #{default}#{' '*tab5}| #{extra}")
108 end
109 model.puts line
110 model.puts "#"
111 model.puts "class #{modelName} < Sequel::Model(:#{m})"
112 model.puts ""
113 #
114 # Add plugins
115 #
116 model.puts " # Plugins"
117 plugin_to_add.each do |p|
118 model.puts " plugin :#{p}"
119 end
120 model.puts ""
121 #
122 # Add table relationships
123 #
124 model.puts " # Referential integrity"
125 # many_to_one relationships
126 DB.foreign_key_list(m).each do |fk|
127 write_association(model, "many_to_one", fk[:table], fk)
128 end
129 # one_to_many relationships
130 # Need to look in each table's foreign_key
131 # querying directly mysql is better here but let's do it totally with Sequel
132 # Just for fun :)
133 DB.tables.each do |t|
134 unless t == m
135 DB.foreign_key_list(t).each do |fk|
136 write_association(model, "one_to_many", t, fk) if fk[:table] == m
137 end
138 end
139 end
140
141 model.puts ""
142 #
143 # Add Validate method
144 #
145 model.puts " # Not nullable cols"
146 model.puts " def validate"
147 list_of_not_nullable_cols = []
148 #list_of_errors_messages = ""
149 list_of_unique_val_cols = []
150 # not nullable columns
151 DB.schema(m).each do |c|
152 info = c[1]
153 list_of_not_nullable_cols.push(c[0]) unless info[:allow_null] or info[:primary_key]
154 end
155
156 # Unique columns
157 DB.indexes(m).each do |name, info|
158 if info[:unique]
159 # There could be several columns for one index
160 info[:columns].each do |col|
161 list_of_unique_val_cols.push(col)
162 end
163 end
164 end
165
166 model.puts(" validates_presence #{list_of_not_nullable_cols}") unless list_of_not_nullable_cols.empty?
167 model.puts(" validates_unique #{list_of_unique_val_cols}") unless list_of_unique_val_cols.empty?
168 model.puts(" end\n")
169 #
170 # Add Referential integrity event
171 #
172 # delete cascade
173 # update cascade
174 model.puts "end"
175 model.close
176end
177
178
179# then create the init.rb file
180init = createfile("init.rb")
181if !init.nil?
182 writeheader(init, "include file to access all models")
183 init.puts "require 'sequel'\n"
184 init.puts "require_relative 'db_connect'\n"
185 init.puts "# MODELS"
186 models_to_create.each do |m|
187 init.puts "require_relative '#{m}'"
188 end
189 init.close
190end
191
192puts "Done."