Class: Oinky::Model::Cpp
- Inherits:
-
Object
- Object
- Oinky::Model::Cpp
- Defined in:
- lib/oinky/cpp_emitter.rb
Class Method Summary collapse
- .instance_type_expression(type) ⇒ Object
- .type_code(h) ⇒ Object
- .value_from_variant(src, type) ⇒ Object
Instance Method Summary collapse
- #accessor_from_tablename(str) ⇒ Object
- #accessor_name(h) ⇒ Object
- #cppify(str) ⇒ Object
- #default_value_expression(coldef) ⇒ Object
-
#emit ⇒ Object
Generate a string, containing the C++ code for the model classes.
- #handle_from_tablename(str) ⇒ Object
- #index_column_ascending(col) ⇒ Object
- #index_column_name(col) ⇒ Object
- #indices(t) ⇒ Object
-
#initialize(schema) ⇒ Cpp
constructor
A new instance of Cpp.
- #instance_type_expression(type) ⇒ Object
- #make_datetime_expression(d) ⇒ Object
- #make_index_handle_name(idef) ⇒ Object
- #make_index_name(idef) ⇒ Object
- #make_table_classname(tn) ⇒ Object
- #schemaname_to_ns(str) ⇒ Object
- #tablename_to_groupname(str) ⇒ Object
- #type_code(h) ⇒ Object
- #value_from_variant(src, type) ⇒ Object
Constructor Details
#initialize(schema) ⇒ Cpp
Returns a new instance of Cpp.
11 12 13 |
# File 'lib/oinky/cpp_emitter.rb', line 11 def initialize(schema) @schema = Oinky::Model.normalize_schema(schema) end |
Class Method Details
.instance_type_expression(type) ⇒ Object
56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
# File 'lib/oinky/cpp_emitter.rb', line 56 def self.instance_type_expression(type) case type when :variant return 'Oinky::variant_cv_t' when :bit return 'bool' when :datetime return 'Oinky::datetime_t' when :string return 'Oinky::db_string' #int when :int8 return 'int8_t' when :int16 return 'int16_t' when :int32 return 'int32_t' when :int64 return 'int64_t' #uint when :uint8 return 'uint8_t' when :uint16 return 'uint16_t' when :uint32 return 'uint32_t' when :uint64 return 'uint64_t' #float when :float32 return 'float32_t' when :float64 return 'float64_t' else # This must be a derived type. It should support this method, to # give us an expression we can use in the target language. return type.instance_type(self) end end |
.type_code(h) ⇒ Object
143 144 145 146 147 |
# File 'lib/oinky/cpp_emitter.rb', line 143 def self.type_code(h) h = h[:type].to_s h[0] = h[0].upcase return 'column_types::' + h end |
.value_from_variant(src, type) ⇒ Object
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 |
# File 'lib/oinky/cpp_emitter.rb', line 99 def self.value_from_variant(src,type) case type when :variant return src when :bit return "#{src}.bit_value()" when :datetime return "#{src}.dt_value()" when :string return "#{src}.string_value()" #int when :int8 return "(int8_t) #{src}.int_value()" when :int16 return "(int16_t) #{src}.int_value()" when :int32 return "(int32_t) #{src}.int_value()" when :int64 return "#{src}.int_value()" #uint when :uint8 return "(uint8_t) #{src}.uint_value()" when :uint16 return "(uint16_t) #{src}.uint_value()" when :uint32 return "(uint32_t) #{src}.uint_value()" when :uint64 return "#{src}.uint_value()" #float when :float32 return "#{src}.f32_value()" when :float64 return "#{src}.f64_value()" else # This must be a derived type. It should support this method, to # give us an expression we can use in the target language. return type.value_from_variant(src, self) end end |
Instance Method Details
#accessor_from_tablename(str) ⇒ Object
22 |
# File 'lib/oinky/cpp_emitter.rb', line 22 def accessor_from_tablename(str) ; cppify(str) ; end |
#accessor_name(h) ⇒ Object
38 39 40 |
# File 'lib/oinky/cpp_emitter.rb', line 38 def accessor_name(h) return cppify(h[:accessor]) end |
#cppify(str) ⇒ Object
15 16 17 |
# File 'lib/oinky/cpp_emitter.rb', line 15 def cppify(str) str.gsub(/($[0-9])|[^a-z0-9A-Z_]/,'_') end |
#default_value_expression(coldef) ⇒ Object
29 30 31 32 33 34 35 36 |
# File 'lib/oinky/cpp_emitter.rb', line 29 def default_value_expression(coldef) d = coldef[:default] return "#{instance_type_expression(coldef[:type])}()" unless d return d.inspect if d.is_a? String return d.inspect if d.is_a? Fixnum return make_datetime_expression(d) if d.is_a? DateTime return d[:cpp] end |
#emit ⇒ Object
Generate a string, containing the C++ code for the model classes.
164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 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 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 |
# File 'lib/oinky/cpp_emitter.rb', line 164 def emit p = Oinky::Detail::Builder.new ns = "namespace #{schemaname_to_ns(@schema[:name])}" p.next("#{ns} {", "} //#{ns}") { p << "using namespace Oinky;" p << "using Oinky::Model::TableBase;" p << "using Oinky::Model::SchemaBase;" p << "using Oinky::db_t;" p << '' p << "class Schema;" tables = @schema[:tables] tables.each{|tn, t| # struct_hdr = "struct #{tablename_to_groupname(t[:name])}" # p << struct_hdr # p.next("{", "}; //#{struct_hdr}") { tbl_classname = make_table_classname(tn) p << '' p << "class #{tbl_classname} : public TableBase" p.next("{", "}; //class #{tbl_classname}") { p << "friend class Schema;" p.write("public:", -1) p.next("struct Row {", "}; //struct Row") { maxw = t[:columns].max_by{|k,col| instance_type_expression(col[:type]).length} maxwlen = maxw ? instance_type_expression(maxw[1][:type]).length : 0 t[:columns].each{|cn,col| if col[:description] col[:description].split("\n").each{|l| p << ("// " + l) } end # The column name is the default value of the accessor name, # but it can be overridden p << Kernel.sprintf("%-#{maxwlen}s %s;", instance_type_expression(col[:type]), accessor_name(col)) } } p << '' p.write("private:", -1) p << "typedef db_t::column_selector_t column_selector_t;" p << 'column_selector_t row_selector;' # index handles indices(t).each {|iname, idef| p << "const db_t::index_handle #{accessor_name(idef)};" } p << '' # update_schema p << 'static void up_schema(db_t::table_handle th)' p.next('{','}') { # Add columns t[:columns].each{|cn, col| p << "TableBase::create_column_if(th, #{cn.inspect}, #{type_code(col)}, #{default_value_expression(col)});" } # Add indices indices(t).each_with_index {|idef,idx| iname, idef = idef # Column definitions names = "idx_column_defs_#{idx}" columns = idef[:columns] p.next("static index_column_def #{names}[] = {", "};") { columns.each_with_index{|col, i| colname = index_column_name(col) ascending = index_column_ascending(col) ? 'true' : 'false' sep = (i == 0 ? '' : ',') p << "#{sep} { db_string(\"#{colname}\"), #{ascending} }" } } unique = idef[:unique] ? 'true' : 'false' p << "TableBase::create_index_if(th, #{iname.inspect}, #{unique}, #{names}, #{names}+#{columns.size} );" } } p << '' p << "template<typename CURSOR>" p.next("void priv_row_from_cursor(Row &row, const CURSOR &crs) {", "}") { # Don't presume that enumeration with index is a consistent # ordering indexed_cols = [] p.next("static const char *column_names[] = {","};") { t[:columns].each{|cn, col| p << "#{cn.inspect}," indexed_cols << col } p << 'NULL' } p.next("TableBase::check_init_row_accessor(", "") { p << "row_selector, " p << "column_names," p << "column_names + #{t[:columns].count}" p << ");" } p.next("variant_cv_t *vals = (variant_cv_t *) ","") { p << "alloca(sizeof(variant_cv_t) * #{t[:columns].count});" } p << "crs.select(row_selector).copy_to(vals, #{t[:columns].count});" p << "// Select values into the target struct" indexed_cols.each_with_index{|col,i| val = value_from_variant("vals[#{i}]", col[:type]) p << "row.#{accessor_name(col)} = #{val};" } } # priv_row_from_cursor p.write("public:", -1) # Constructor - initialize index handles. p.next("#{tbl_classname}(db_t::table_handle _th, db_t &db) : TableBase(_th, db)","{}") { indices(t).each {|iname, idef| p << ",#{accessor_name(idef)}(TableBase::get_index_handle(_th, \"#{iname}\"))" } } # Row accessors p << '' p.next("void row_from_cursor(Row &row, const db_t::index_cursor_handle &crs) {", "}") { p << "priv_row_from_cursor(row, crs);" } p.next("void row_from_cursor(Row &row, const db_t::table_cursor_handle &crs) {", "}") { p << "priv_row_from_cursor(row, crs);" } } # class "#{tbl_classname}" } # tables.each {} p << '' p << "class Schema : public SchemaBase" p.next("{","}; //class Schema") { p.next("static void up_schema(db_t &db) {","}") { tables.each{|tn, t| tbl_classname = make_table_classname(tn) p << "#{tbl_classname}::up_schema(SchemaBase::get_table_handle(db, #{tn.inspect}));"; } } p << '' p.write("public:", -1) # Table accessors tables.each {|tn, tdef| tbl_classname = make_table_classname(tn) p << "const #{tbl_classname} #{accessor_name(tdef)};" } p << '' p.next("Schema(db_t &db) : SchemaBase(db, &up_schema)","{}") { tables.each {|tn, tdef| p << ",#{accessor_name(tdef)}(SchemaBase::get_table_handle(db, #{tn.inspect}), db)" } } } } # namespace <schemaname> return p.format end |
#handle_from_tablename(str) ⇒ Object
21 |
# File 'lib/oinky/cpp_emitter.rb', line 21 def handle_from_tablename(str) ; "#{cppify(str)}_handle" ; end |
#index_column_ascending(col) ⇒ Object
47 48 49 50 51 |
# File 'lib/oinky/cpp_emitter.rb', line 47 def index_column_ascending(col) return col[:ascending] if col.is_a? Hash # ascending is the default return true end |
#index_column_name(col) ⇒ Object
42 43 44 45 46 |
# File 'lib/oinky/cpp_emitter.rb', line 42 def index_column_name(col) return col if col.is_a? String return col.to_s if col.is_a? Symbol return index_column_name(col[:name]) end |
#indices(t) ⇒ Object
159 160 161 |
# File 'lib/oinky/cpp_emitter.rb', line 159 def indices(t) t[:indices] || t[:indexes] || [] end |
#instance_type_expression(type) ⇒ Object
53 54 55 |
# File 'lib/oinky/cpp_emitter.rb', line 53 def instance_type_expression(type) self.class.instance_type_expression(type) end |
#make_datetime_expression(d) ⇒ Object
24 25 26 27 |
# File 'lib/oinky/cpp_emitter.rb', line 24 def make_datetime_expression(d) "Oinky::datetime_t::compose(#{d.year-1900},#{d.month - 1},#{d.day - 1}," + "#{d.hour},#{d.minute},#{d.second},#{(d.second_fraction * 1000000).to_i})" end |
#make_index_handle_name(idef) ⇒ Object
152 153 154 |
# File 'lib/oinky/cpp_emitter.rb', line 152 def make_index_handle_name(idef) "_idx_handle__#{make_index_name(idef)}" end |
#make_index_name(idef) ⇒ Object
149 150 151 |
# File 'lib/oinky/cpp_emitter.rb', line 149 def make_index_name(idef) cppify(idef[:name]) end |
#make_table_classname(tn) ⇒ Object
155 156 157 |
# File 'lib/oinky/cpp_emitter.rb', line 155 def make_table_classname(tn) "CTable_#{cppify(tn)}" end |
#schemaname_to_ns(str) ⇒ Object
19 |
# File 'lib/oinky/cpp_emitter.rb', line 19 def schemaname_to_ns(str) ; cppify(str) ; end |
#tablename_to_groupname(str) ⇒ Object
20 |
# File 'lib/oinky/cpp_emitter.rb', line 20 def tablename_to_groupname(str) ; cppify(str) ; end |
#type_code(h) ⇒ Object
140 141 142 |
# File 'lib/oinky/cpp_emitter.rb', line 140 def type_code(h) self.class.type_code(h) end |
#value_from_variant(src, type) ⇒ Object
96 97 98 |
# File 'lib/oinky/cpp_emitter.rb', line 96 def value_from_variant(src,type) self.class.value_from_variant(src,type) end |