Class: NoSE::Random::StatementGenerator
Overview
Generates random queries over entities in a given model
Instance Method Summary collapse
-
#initialize(model) ⇒ StatementGenerator
constructor
A new instance of StatementGenerator.
-
#random_connection(entity) ⇒ Object
Generate a random connection for an Insert.
-
#random_delete ⇒ Delete
Generate a new random deletion of entities in the model.
-
#random_graph(max_nodes) ⇒ Object
Produce a random query graph over the entity graph.
-
#random_insert(connect = true) ⇒ Insert
Generate a new random insertion to entities in the model.
-
#random_path(max_length) ⇒ KeyPath
Return a random path through the entity graph.
-
#random_query(path_length = 3, selected_fields = 2, condition_count = 2, order = false) ⇒ Query
Generate a new random query from entities in the model.
-
#random_select(path, selected_fields) ⇒ Set<Fields::Field>
Get random fields to select for a Query.
-
#random_settings(path, updated_fields) ⇒ String
Get random settings for an update.
-
#random_statement(weights = { query: 80, insert: 10, update: 5, delete: 5 }) ⇒ Statement
Produce a random statement according to a given set of weights.
-
#random_update(path_length = 1, updated_fields = 2, condition_count = 1) ⇒ Update
Generate a new random update of entities in the model.
Constructor Details
#initialize(model) ⇒ StatementGenerator
Returns a new instance of StatementGenerator.
126 127 128 |
# File 'lib/nose/random.rb', line 126 def initialize(model) @model = model end |
Instance Method Details
#random_connection(entity) ⇒ Object
Generate a random connection for an Insert
146 147 148 149 150 151 |
# File 'lib/nose/random.rb', line 146 def random_connection(entity) connections = entity.foreign_keys.values.sample(2) 'AND CONNECT TO ' + connections.map do |connection| "#{connection.name}(?)" end.join(', ') end |
#random_delete ⇒ Delete
Generate a new random deletion of entities in the model
181 182 183 184 185 186 187 188 189 |
# File 'lib/nose/random.rb', line 181 def random_delete path = random_path(1) from = [path.first.parent.name] + path.entries[1..-1].map(&:name) delete = "DELETE #{from.first} FROM #{from.join '.'} " + random_where_clause(path, 1) Statement.parse delete, @model end |
#random_graph(max_nodes) ⇒ Object
Produce a random query graph over the entity graph
274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 |
# File 'lib/nose/random.rb', line 274 def random_graph(max_nodes) graph = QueryGraph::Graph.new last_node = graph.add_node @model.entities.values.sample while graph.size < max_nodes # Get the possible foreign keys to use keys = last_node.entity.foreign_keys.values keys.reject! { |key| graph.nodes.map(&:entity).include? key.entity } break if keys.empty? # Pick a random foreign key to traverse next_key = keys.sample graph.add_edge last_node, next_key.entity, next_key # Select a new node to start from, making sure we pick one # that still has valid outgoing edges last_node = graph.nodes.reject do |node| (node.entity.foreign_keys.each_value.map(&:entity) - graph.nodes.map(&:entity)).empty? end.sample break if last_node.nil? end graph end |
#random_insert(connect = true) ⇒ Insert
Generate a new random insertion to entities in the model
132 133 134 135 136 137 138 139 140 141 142 143 |
# File 'lib/nose/random.rb', line 132 def random_insert(connect = true) entity = @model.entities.values.sample settings = entity.fields.each_value.map do |field| "#{field.name}=?" end.join ', ' insert = "INSERT INTO #{entity.name} SET #{settings} " # Optionally add connections to other entities insert += random_connection(entity) if connect Statement.parse insert, @model end |
#random_path(max_length) ⇒ KeyPath
Return a random path through the entity graph
251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 |
# File 'lib/nose/random.rb', line 251 def random_path(max_length) # Pick the start of path weighted based on # the number of deges from each entity pick = Pickup.new(Hash[@model.entities.each_value.map do |entity| [entity, entity.foreign_keys.length] end]) path = [pick.pick.id_field] while path.length < max_length # Find a list of keys to entities we have not seen before last_entity = path.last.entity keys = last_entity.foreign_keys.values keys.reject! { |key| path.map(&:entity).include? key.entity } break if keys.empty? # Add a random new key to the path path << keys.sample end KeyPath.new path end |
#random_query(path_length = 3, selected_fields = 2, condition_count = 2, order = false) ⇒ Query
Generate a new random query from entities in the model
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 |
# File 'lib/nose/random.rb', line 193 def random_query(path_length = 3, selected_fields = 2, condition_count = 2, order = false) path = random_path path_length graph = QueryGraph::Graph.from_path path conditions = [ Condition.new(path.entities.first.fields.values.sample, :'=', nil) ] condition_count -= 1 new_fields = random_where_conditions(path, condition_count, conditions.map(&:field).to_set) conditions += new_fields.map do |field| Condition.new(field, :'>', nil) end conditions = Hash[conditions.map do |condition| [condition.field.id, condition] end] params = { select: random_select(path, selected_fields), model: @model, graph: graph, key_path: graph.longest_path, entity: graph.longest_path.first.parent, conditions: conditions, order: order ? [graph.entities.to_a.sample.fields.values.sample] : [] } query = Query.new params, nil query.hash query end |
#random_select(path, selected_fields) ⇒ Set<Fields::Field>
Get random fields to select for a Query
231 232 233 234 235 236 237 238 |
# File 'lib/nose/random.rb', line 231 def random_select(path, selected_fields) fields = Set.new while fields.length < selected_fields fields.add path.entities.sample.fields.values.sample end fields end |
#random_settings(path, updated_fields) ⇒ String
Get random settings for an update
169 170 171 172 173 174 175 176 177 |
# File 'lib/nose/random.rb', line 169 def random_settings(path, updated_fields) # Don't update key fields update_fields = path.entities.first.fields.values update_fields.reject! { |field| field.is_a? Fields::IDField } update_fields.sample(updated_fields).map do |field| "#{field.name}=?" end.join ', ' end |
#random_statement(weights = { query: 80, insert: 10, update: 5, delete: 5 }) ⇒ Statement
Produce a random statement according to a given set of weights
242 243 244 245 246 247 |
# File 'lib/nose/random.rb', line 242 def random_statement(weights = { query: 80, insert: 10, update: 5, delete: 5 }) pick = Pickup.new(weights) type = pick.pick send(('random_' + type.to_s).to_sym) end |
#random_update(path_length = 1, updated_fields = 2, condition_count = 1) ⇒ Update
Generate a new random update of entities in the model
155 156 157 158 159 160 161 162 163 164 165 |
# File 'lib/nose/random.rb', line 155 def random_update(path_length = 1, updated_fields = 2, condition_count = 1) path = random_path(path_length) settings = random_settings path, updated_fields from = [path.first.parent.name] + path.entries[1..-1].map(&:name) update = "UPDATE #{from.first} FROM #{from.join '.'} " \ "SET #{settings} " + random_where_clause(path, condition_count) Statement.parse update, @model end |