module DataMetaDom::OraLexer

Definition for generating Oracle 11 and later 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

INT_TYPES

Integer types

NOT_NULL

Not null (required) wording per Oracle DDL syntax

SQL_TYPES

Mapping from DataMeta DOM standard types to correspondent Oracle types renderer lambdas.

Public Instance Methods

autoGenClauseIfAny(out, record, field) click to toggle source

Renders autoincrement the very special Oracle way, via a sequence FIXME: need to check the auto hint

@return empty string

# File lib/dataMetaDom/ora.rb, line 142
    def autoGenClauseIfAny(out, record, field)
        if record.identity && record.identity.length == 1 && field.name == record.identity[0] &&
                field.dataType.type == DataMetaDom::INT
            ns, entityName = DataMetaDom.splitNameSpace record.name
            seqName = "#{entityName}_#{field.name}_sq"
# Transaction separators are important for triggers and sequences
            out.crSeqs.puts %|
CREATE SEQUENCE #{seqName};

/
|
=begin rdoc
 To make the sequence used automatically:
CREATE OR REPLACE TRIGGER #{entityName}_#{field.name}_trg
BEFORE INSERT ON #{entityName}
FOR EACH ROW

BEGIN
  SELECT #{seqName}.NEXTVAL
  INTO   :new.#{field.name}
  FROM   dual;
END;
=end
            out.drSeqs.puts %|

drop SEQUENCE #{seqName};
/
|
        end

        ''
    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/ora.rb, line 213
def fkName(bareEntityName, index)
    "fk_#{bareEntityName}_#{index}"
end
genDdl(parser, outDir) click to toggle source

Generate the Oracle 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/ora.rb, line 283
def genDdl(parser, outDir)
    out = SqlOutput.new(outDir)
    begin
        parser.records.each_key { |r|
            renderRecord(out, parser, r)
        }
    ensure
        out.close
    end
end
renderField(out, 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/ora.rb, line 184
def renderField(out, 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, ty.scale, 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, idField.dataType.scale, field.isRequired
              end
    createStatement << ",\n" unless isFirstField
    createStatement << "\t#{field.name} #{typeDef}#{autoGenClauseIfAny(out, 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/ora.rb, line 224
    def renderRecord(out, parser, recordKey)
        record = parser.records[recordKey]
        ns, entityName = DataMetaDom.splitNameSpace record.name
        isFirstField = true
        # Oracle does not have neatly defined feature of dropping table if it exists
        # https://community.oracle.com/thread/2421779?tstart=0
        out.drop.puts %|\ndrop table #{entityName};
/
|
        fkNumber = 1 # to generate unique names that fit in 64 characters of identifier max length for Oracle
        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(out, 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\tconstraint uq_#{entityName}_#{uqNumber} unique(#{uq.args.join(', ')})"
                uqNumber += 1 # to generate unique names that fit in 30 characters of identifier max length for Oracle
            }
        end
        unless record.indexes.empty?
            ixNumber = 1
            record.indexes.each_value { |ix|
                out.ixes.puts %|
CREATE INDEX #{entityName}_#{ixNumber} ON #{entityName}(#{ix.args.join(', ')});
/
|
#                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 Oracle
            }
        end
        createStatement << "\n);\n/\n"

        out.create.puts createStatement
    end