Module: DataMetaDom::MySqlLexer
- Defined in:
- lib/dataMetaDom/mySql.rb
Overview
Definition for generating MySQL 5 artifacts such as schemas, select statements, ORM input files etc etc
TODO this isn’t a bad way, but beter use templating next time such as ERB.
For command line details either check the new method’s source or the README.rdoc file, the usage section.
Defined Under Namespace
Classes: SqlOutput
Constant Summary collapse
- INT_TYPES =
Integer types
{2 => 'smallint', 4 => 'int', 8 => 'bigint'}
- FLOAT_TYPES =
Float types
{4 => 'float', 8 => 'double'}
- NOT_NULL =
Not null (required) wording per MySQL DDL syntax
' not null'- SQL_TYPES =
Mapping from DataMeta DOM standard types to correspondent MySQL types renderer lambdas.
{ INT => lambda { |len, isReq| concreteType = INT_TYPES[len] raise "Invalid integer type length #{len} " unless concreteType "#{concreteType}#{isReq ? NOT_NULL : ''}" }, DataMetaDom::FLOAT => lambda { |len, isReq| concreteType = FLOAT_TYPES[len] raise "Invalid integer type length #{len} " unless concreteType "#{concreteType}#{isReq ? NOT_NULL : ''}" }, STRING => lambda { |len, isReq| "varchar(#{len})#{isReq ? NOT_NULL : ''}" }, DATETIME => lambda { |len, isReq| "datetime#{isReq ? NOT_NULL : ''}" }, BOOL => lambda { |len, isReq| "bool#{isReq ? NOT_NULL : ''}" } }
Instance Method Summary collapse
-
#autoGenClauseIfAny(record, field) ⇒ Object
Builds and returns an autoincrement clause if applicable, for the given record and the field.
-
#fkName(bareEntityName, index) ⇒ Object
Builds and returns the foreign key name for the given entity (Record) name and the counting number of these.
-
#genDdl(parser, outDir) ⇒ Object
Generate the MySQL DDL from the given Model into the given output directory.
-
#renderField(createStatement, parser, record, fieldKey, isFirstField) ⇒ Object
Renders the given field into create statement.
-
#renderRecord(out, parser, recordKey) ⇒ Object
Render SQL record with for the given model into the given output.
Instance Method Details
#autoGenClauseIfAny(record, field) ⇒ Object
Builds and returns an autoincrement clause if applicable, for the given record and the field.
If the field is the one and only identity on the record and if it is an integral type, returns the auto increment clause, otherwise returns and empty string.
137 138 139 140 |
# File 'lib/dataMetaDom/mySql.rb', line 137 def autoGenClauseIfAny(record, field) record.identity && record.identity.length == 1 && field.name == record.identity[0] && field.dataType.type == DataMetaDom::INT ? ' AUTO_INCREMENT' : '' end |
#fkName(bareEntityName, index) ⇒ Object
Builds and returns the foreign key name for the given entity (Record) name and the counting number of these.
-
Parameters:
-
bareEntityName- the entity name without the namespace -
index- an integer, an enumerated counting number, starting from one. For each subsequent FK this number is incremented.
-
182 183 184 |
# File 'lib/dataMetaDom/mySql.rb', line 182 def fkName(, index) "fk_#{bareEntityName}_#{index}" end |
#genDdl(parser, outDir) ⇒ Object
Generate the MySQL DDL from the given Model into the given output directory.
-
Parameters
-
parser- an instance of a Model -
outDir- a String, the directory to generate the DDL into.
-
244 245 246 247 248 249 250 251 252 253 |
# File 'lib/dataMetaDom/mySql.rb', line 244 def genDdl(parser, outDir) out = SqlOutput.new(outDir) begin parser.records.each_key { |r| renderRecord(out, parser, r) } ensure out.close end end |
#renderField(createStatement, parser, record, fieldKey, isFirstField) ⇒ Object
Renders the given field into create statement.
-
Parameters:
-
createStatement- the create statement to append the field definition to. -
parser- the instance of the Model -
record- the instance of the Record to which the field belongs -
fieldKey- the full name of the field to render turned into a symbol. -
isFirstField- the boolean, true if the field is first in the create statement.
-
151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 |
# File 'lib/dataMetaDom/mySql.rb', line 151 def renderField(createStatement, parser, record, fieldKey, isFirstField) field = record[fieldKey] ty = field.dataType stdRenderer = SQL_TYPES[ty.type] typeEnum = parser.enums[ty.type] typeRec = parser.records[ty.type] typeDef = if stdRenderer stdRenderer.call ty.length, field.isRequired elsif typeEnum "enum('#{typeEnum.values.join("','")}')" elsif typeRec raise "Invalid ref to #{typeRec} - it has no singular ID" unless typeRec.identity.length == 1 idField = typeRec[typeRec.identity[0]] idRenderer = SQL_TYPES[idField.dataType.type] raise 'Only one-level prim type references only allowed in this version' unless idRenderer idRenderer.call idField.dataType.length, field.isRequired else raise ArgumentError, "Unsupported datatype #{ty}" end createStatement << ",\n" unless isFirstField createStatement << "\t#{field.name} #{typeDef}#{autoGenClauseIfAny(record, field)}" end |
#renderRecord(out, parser, recordKey) ⇒ Object
Render SQL record with for the given model into the given output.
-
Parameters
-
out- an instance of SqlOutput -
parser- an instance of Model -
recordKey- full name of the record datatype including namespeace if any turned into a symbol.
-
193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 |
# File 'lib/dataMetaDom/mySql.rb', line 193 def renderRecord(out, parser, recordKey) record = parser.records[recordKey] ns, entityName = DataMetaDom.splitNameSpace record.name isFirstField = true out.drop.puts "\ndrop table if exists #{entityName};" fkNumber = 1 # to generate unique names that fit in 64 characters of identifier max length for MySQL record.refs.select { |r| r.type == Reference::RECORD }.each { |ref| ns, fromEntityBareName = DataMetaDom.splitNameSpace ref.fromEntity.name ns, toEntityBareName = DataMetaDom.splitNameSpace ref.toEntity.name out.couple.puts "alter table #{fromEntityBareName} add constraint #{fkName(fromEntityBareName, fkNumber)} "\ " foreign key (#{ref.fromField.name}) references #{toEntityBareName}(#{ref.toFields.name});" out.uncouple.puts "alter table #{fromEntityBareName} drop foreign key #{fkName(fromEntityBareName, fkNumber)};" fkNumber += 1 } ids = record.identity ? record.identity.args : [] createStatement = "create table #{entityName} (\n" fieldKeys = [] << ids.map { |i| i.to_s }.sort.map { |i| i.to_sym } \ << record.fields.keys.select { |k| !ids.include?(k) }.map { |k| k.to_s }.sort.map { |k| k.to_sym } fieldKeys.flatten.each { |f| renderField(createStatement, parser, record, f, isFirstField) isFirstField = false } if record.identity && record.identity.length > 0 createStatement << ",\n\tprimary key(#{ids.sort.join(', ')})" end unless record.uniques.empty? uqNumber = 1 record.uniques.each_value { |uq| createStatement << ",\n\tunique uq_#{entityName}_#{uqNumber}(#{uq.args.join(', ')})" uqNumber += 1 # to generate unique names that fit in 64 characters of identifier max length for MySQL } end unless record.indexes.empty? ixNumber = 1 record.indexes.each_value { |ix| createStatement << ",\n\tindex ix_#{entityName}_#{ixNumber}(#{ix.args.join(', ')})" ixNumber += 1 # to generate unique names that fit in 64 characters of identifier max length for MySQL } end createStatement << "\n) Engine=InnoDB;\n\n" # MyISAM, the default engine does not support FKs out.create.puts createStatement end |