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
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
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
Generate the Oracle 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/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
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/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
Render SQL record with for the given model into the given output.
-
Parameters
# 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