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

autoGenClauseIfAny(record, field) click to toggle source

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
fkName(bareEntityName, index) click to toggle source

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
genDdl(parser, outDir) click to toggle source

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.

# 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
renderField(createStatement, parser, record, fieldKey, isFirstField) click to toggle source

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.

# 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
renderRecord(out, parser, recordKey) click to toggle source

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.

# 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