Module: DataMetaDom::OraLexer
- Defined in:
- lib/dataMetaDom/ora.rb
Overview
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.
Defined Under Namespace
Classes: SqlOutput
Constant Summary collapse
- INT_TYPES =
Integer types
{2 => 'number(6)', 4 => 'number(9)', 8 => 'number(38)'}
- NOT_NULL =
Not null (required) wording per Oracle DDL syntax
' not null'- SQL_TYPES =
Mapping from DataMeta DOM standard types to correspondent Oracle types renderer lambdas.
{ INT => lambda { |len, scale, isReq| concreteType = INT_TYPES[len] raise "Invalid integer type length #{len} " unless concreteType "#{concreteType}#{isReq ? NOT_NULL : ''}" }, STRING => lambda { |len, scale, isReq| "nvarchar2(#{len})#{isReq ? NOT_NULL : ''}" }, DATETIME => lambda { |len, scale, isReq| "timestamp#{isReq ? NOT_NULL : ''}" }, # Boolean implementation in Oracle is not optimal, see the doc: # http://docs.oracle.com/cd/B19306_01/olap.102/b14346/dml_datatypes004.htm BOOL => lambda { |len, scale, isReq| "boolean#{isReq ? NOT_NULL : ''}" }, CHAR => ->(len, scale, isReq) { "nchar(#{len})#{isReq ? NOT_NULL : ''}" }, NUMERIC => ->(len, scale, isReq) { "number(#{len}, #{scale})#{isReq ? NOT_NULL : ''}" } }
Instance Method Summary collapse
-
#autoGenClauseIfAny(out, record, field) ⇒ Object
Renders autoincrement the very special Oracle way, via a sequence FIXME: need to check the auto hint.
-
#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 Oracle DDL from the given Model into the given output directory.
-
#renderField(out, 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(out, record, field) ⇒ Object
Renders autoincrement the very special Oracle way, via a sequence FIXME: need to check the auto hint
142 143 144 145 146 147 148 149 150 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/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) ⇒ 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.
-
213 214 215 |
# File 'lib/dataMetaDom/ora.rb', line 213 def fkName(, index) "fk_#{}_#{index}" end |
#genDdl(parser, outDir) ⇒ Object
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.
-
283 284 285 286 287 288 289 290 291 292 |
# 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) ⇒ 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.
-
184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 |
# 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) ⇒ 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.
-
224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 |
# 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 |