module DataMetaDom::MySqlLexer
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.
Constants
- FLOAT_TYPES
Float types
- INT_TYPES
Integer types
- NOT_NULL
Not null (required) wording per MySQL DDL syntax
- SQL_TYPES
Mapping from DataMeta DOM standard types to correspondent MySQL types renderer lambdas.
Public Instance Methods
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.
# File lib/dataMetaDom/mySql.rb, line 145 def autoGenClauseIfAny(record, field) record.identity && record.identity.length == 1 && field.name == record.identity[0] && field.dataType.type == DataMetaDom::INT ? ' AUTO_INCREMENT' : '' end
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.
-
# File lib/dataMetaDom/mySql.rb, line 190 def fkName(bareEntityName, index) "fk_#{bareEntityName}_#{index}" end
Generate the MySQL DDL from the given Model
into the given output directory.
-
Parameters
-
parser
- an instance of aModel
-
outDir
- a String, the directory to generate the DDL into.
-
# File lib/dataMetaDom/mySql.rb, line 252 def genDdl(parser, outDir) out = SqlOutput.new(outDir) begin parser.records.each_key { |r| renderRecord(out, parser, r) } ensure out.close end end
Renders the given field into create statement.
-
Parameters:
-
createStatement
- the create statement to append the field definition to. -
parser
- the instance of theModel
-
record
- the instance of theRecord
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.
-
# File lib/dataMetaDom/mySql.rb, line 159 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
Render SQL record with for the given model into the given output.
-
Parameters
# File lib/dataMetaDom/mySql.rb, line 201 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 }.map { |i| i.to_sym } \ << record.fields.keys.select { |k| !ids.include?(k) }.map { |k| k.to_s }.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.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