Class: Foobara::Autocrud::CreateCommands

Inherits:
Command
  • Object
show all
Defined in:
foobara-autocrud-0.0.1/src/create_commands.rb

Overview

TODO: autocrud commands! commands:

CreateUser UpdateUserAtom UpdateUserAggregate

can records be created in this situation?? or only updated?

HardDeleteUser AppendToUserRatings RemoveFromUserRatings FindUser FindUserBy QueryUser

types:

User

UserAttributes
UserCreateAttributes
UserUpdateAtomAttributes
  remove all required and defaults
  primary key required
UserUpdateAggregateAttributes
  convert all associations to their XUpdateAggregateAttributes types??
UserPrimaryKeyType ??

if primary key created by db

no primary key in UserCreateAttributes

if primary key created externally

primary key in UserCreateAttributes and is required

TODO: consider moving helper methods here into their own commands?

Constant Summary collapse

ALLOWED_COMMANDS =
%i[
  create
  update_atom
  update_aggregate
  hard_delete
  find
  find_by
  query
  query_all
  append
].freeze

Constants included from TruncatedInspect

TruncatedInspect::MAX_LENGTH

Instance Attribute Summary collapse

Attributes included from CommandPatternImplementation::Concerns::Subcommands

#is_subcommand

Attributes included from CommandPatternImplementation::Concerns::Runtime

#exception, #outcome

Attributes included from CommandPatternImplementation::Concerns::Errors

#error_collection

Attributes included from CommandPatternImplementation::Concerns::Inputs

#inputs, #raw_inputs

Instance Method Summary collapse

Methods inherited from Command

install!, reset_all

Methods included from Concern

foobara_class_methods_module_for, foobara_concern?, included

Methods included from CommandPatternImplementation::Concerns::Reflection

#initialize

Methods included from CommandPatternImplementation::Concerns::DomainMappers

#domain_map, #domain_map!, #run_mapped_subcommand!

Methods included from CommandPatternImplementation::Concerns::Subcommands

#run_subcommand!, #subcommand?

Methods included from CommandPatternImplementation::Concerns::Entities

#load_entities, #load_records

Methods included from CommandPatternImplementation::Concerns::Transactions

#auto_detect_current_transactions, #commit_transaction, #open_transaction, #opened_transactions, #relevant_entity_classes, #rollback_transaction, #transactions

Methods included from CommandPatternImplementation::Concerns::StateMachine

#state_machine

Methods included from CommandPatternImplementation::Concerns::Runtime

#halt!, #run, #run!, #run_execute, #succeed, #success?, #validate, #validate_records

Methods included from CommandPatternImplementation::Concerns::Errors

#initialize

Methods included from CommandPatternImplementation::Concerns::Inputs

#cast_and_validate_inputs, #initialize, #method_missing, #respond_to_missing?, #respond_to_missing_for_inputs?

Methods included from TruncatedInspect

#inspect, truncating

Dynamic Method Handling

This class handles dynamic methods through the method_missing method in the class Foobara::CommandPatternImplementation::Concerns::Inputs

Instance Attribute Details

#created_commandsObject



79
80
81
# File 'foobara-autocrud-0.0.1/src/create_commands.rb', line 79

def created_commands
  @created_commands ||= []
end

Instance Method Details

#commands_to_createObject



83
84
85
86
87
88
89
# File 'foobara-autocrud-0.0.1/src/create_commands.rb', line 83

def commands_to_create
  @commands_to_create ||= if commands == :all || commands.nil?
                            ALLOWED_COMMANDS
                          else
                            Util.array(commands)
                          end
end

#create_append_command(path_to_collection, association_type) ⇒ Object



371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
# File 'foobara-autocrud-0.0.1/src/create_commands.rb', line 371

def create_append_command(path_to_collection, association_type)
  entity_class = self.entity_class
  start = path_to_collection.size - 2
  start = 0 if start < 0
  collection_name = path_to_collection[start..start + 1]
  collection_name = collection_name.map { |part| Util.classify(part) }.join

  domain = entity_class.domain
  # TODO: group these by entity name?
  command_name = [*domain.scoped_full_path,
                  "AppendTo#{entity_class.entity_type.scoped_short_name}#{collection_name}"].join("::")

  entity_input_name = Util.underscore_sym(entity_class.entity_type.scoped_short_name)

  Util.make_class(command_name, Foobara::Command) do
    define_method :path_to_collection do
      path_to_collection
    end

    define_method :entity_input_name do
      entity_input_name
    end

    # TODO: can't use attributes: :attributes but should be able to.
    # Allow a hash to create these these things?
    inputs type: :attributes,
           element_type_declarations: {
             entity_input_name => entity_class,
             element_to_append: association_type.target_class
           },
           required: [entity_input_name, :element_to_append]

    result association_type.target_class

    to_load entity_input_name

    def execute
      append_record_to_collection

      element_to_append
    end

    attr_accessor :new_collection

    def append_record_to_collection
      collection = DataPath.value_at(path_to_collection, record)

      self.new_collection = [*collection, element_to_append]

      DataPath.set_value_at(record, new_collection, path_to_collection)
    end

    def record
      inputs[entity_input_name]
    end
  end
end

#create_append_commandsObject



356
357
358
359
360
361
362
363
364
365
366
367
368
369
# File 'foobara-autocrud-0.0.1/src/create_commands.rb', line 356

def create_append_commands
  commands = []

  entity_class.associations.each_pair do |data_path, type|
    data_path = DataPath.parse(data_path)
    if data_path.simple_collection?
      path = data_path.path[0..-2]
      commands << create_append_command(path, type)
      commands << create_remove_command(path, type)
    end
  end

  commands
end

#create_commandsObject



65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'foobara-autocrud-0.0.1/src/create_commands.rb', line 65

def create_commands
  commands_to_create.each do |command_symbol|
    method = if command_symbol == :append
               "create_append_commands"
             else
               "create_#{command_symbol}_command"
             end

    created_commands << send(method)
  end

  self.created_commands = created_commands.flatten
end

#create_create_commandObject



161
162
163
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
# File 'foobara-autocrud-0.0.1/src/create_commands.rb', line 161

def create_create_command
  entity_class = self.entity_class
  domain = entity_class.domain
  command_name = [*domain.scoped_full_path, "Create#{entity_class.entity_type.scoped_short_name}"].join("::")

  Util.make_class(command_name, Foobara::Command) do
    define_method :entity_class do
      entity_class
    end

    # TODO: does this work with User instead of :User ?
    # We can't come up with a cleaner way to do this?
    # TODO: we should be allowed to just pass the type instead of transforming it to declaration_data
    inputs entity_class.attributes_type
    result entity_class

    def execute
      create_record

      record
    end

    attr_accessor :record

    def create_record
      self.record = entity_class.create(inputs)
    end
  end
end

#create_find_by_commandObject



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
# File 'foobara-autocrud-0.0.1/src/create_commands.rb', line 266

def create_find_by_command
  entity_class = self.entity_class
  domain = entity_class.domain
  command_name = [*domain.scoped_full_path, "Find#{entity_class.entity_type.scoped_short_name}By"].join("::")

  Util.make_class(command_name, Foobara::Command) do
    define_method :entity_class do
      entity_class
    end

    # TODO: can't use attributes: :attributes but should be able to.
    inputs entity_class.attributes_for_find_by
    result entity_class

    possible_error Entity::NotFoundError

    def execute
      load_record

      record
    end

    attr_accessor :record

    def load_record
      self.record = entity_class.find_by(inputs)

      unless record
        add_runtime_error Entity::NotFoundError.new(inputs, entity_class:)
      end
    end
  end
end

#create_find_commandObject



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
# File 'foobara-autocrud-0.0.1/src/create_commands.rb', line 227

def create_find_command
  entity_class = self.entity_class
  domain = entity_class.domain
  command_name = [*domain.scoped_full_path, "Find#{entity_class.entity_type.scoped_short_name}"].join("::")

  Util.make_class(command_name, Foobara::Command) do
    define_method :entity_class do
      entity_class
    end

    inputs entity_class.primary_key_attribute => entity_class.primary_key_type
    result entity_class

    possible_error Entity::NotFoundError

    def execute
      load_record

      record
    end

    attr_accessor :record

    def load_record
      self.record = entity_class.load(record_id)
    rescue Entity::NotFoundError => e
      add_runtime_error e
    end

    def primary_key_attribute
      entity_class.primary_key_attribute
    end

    def record_id
      inputs[primary_key_attribute]
    end
  end
end

#create_hard_delete_commandObject



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
# File 'foobara-autocrud-0.0.1/src/create_commands.rb', line 191

def create_hard_delete_command
  entity_class = self.entity_class
  domain = entity_class.domain
  command_name = [*domain.scoped_full_path, "HardDelete#{entity_class.entity_type.scoped_short_name}"].join("::")

  Util.make_class(command_name, Foobara::Command) do
    singleton_class.define_method :record_method_name do
      @record_method_name ||= Util.underscore(entity_class.entity_type.scoped_short_name)
    end

    foobara_delegate :record_method_name, to: :class

    def record
      send(record_method_name)
    end

    # TODO: does this work with User instead of :User ?
    # We can't come up with a cleaner way to do this?
    # TODO: make this work with entity classes!! no reason not to and very inconvenient
    inputs Util.underscore(entity_class.entity_type.scoped_short_name) => entity_class
    result entity_class

    load_all

    def execute
      delete_record

      record
    end

    def delete_record
      record.hard_delete!
    end
  end
end

#create_query_all_commandObject



328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
# File 'foobara-autocrud-0.0.1/src/create_commands.rb', line 328

def create_query_all_command
  entity_class = self.entity_class
  domain = entity_class.domain
  command_name = [*domain.scoped_full_path, "QueryAll#{entity_class.entity_type.scoped_short_name}"].join("::")

  Util.make_class(command_name, Foobara::Command) do
    define_method :entity_class do
      entity_class
    end

    # TODO: can't use attributes: :attributes but should be able to.
    inputs({})
    result [entity_class]

    def execute
      run_query

      records
    end

    attr_accessor :records

    def run_query
      self.records = entity_class.all
    end
  end
end

#create_query_commandObject



300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
# File 'foobara-autocrud-0.0.1/src/create_commands.rb', line 300

def create_query_command
  entity_class = self.entity_class
  domain = entity_class.domain
  command_name = [*domain.scoped_full_path, "Query#{entity_class.entity_type.scoped_short_name}"].join("::")

  Util.make_class(command_name, Foobara::Command) do
    define_method :entity_class do
      entity_class
    end

    # TODO: can't use attributes: :attributes but should be able to.
    inputs entity_class.attributes_for_find_by
    result [entity_class]

    def execute
      run_query

      records
    end

    attr_accessor :records

    def run_query
      self.records = entity_class.find_many_by(inputs)
    end
  end
end

#create_remove_command(path_to_collection, association_type) ⇒ Object



429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
# File 'foobara-autocrud-0.0.1/src/create_commands.rb', line 429

def create_remove_command(path_to_collection, association_type)
  entity_class = self.entity_class
  start = path_to_collection.size - 2
  start = 0 if start < 0
  collection_name = path_to_collection[start..start + 1]
  collection_name = collection_name.map { |part| Util.classify(part) }.join

  domain = entity_class.domain
  # TODO: group these by entity name?
  command_name = [*domain.scoped_full_path,
                  "RemoveFrom#{entity_class.entity_type.scoped_short_name}#{collection_name}"].join("::")

  entity_input_name = Util.underscore_sym(entity_class.entity_type.scoped_short_name)

  Util.make_class(command_name, Foobara::Command) do
    Util.make_class("#{command_name}::ElementNotInCollectionError", Foobara::RuntimeError) do
      class << self
        # TODO: make this the default
        def context_type_declaration
          {}
        end
      end
    end

    define_method :path_to_collection do
      path_to_collection
    end

    define_method :entity_input_name do
      entity_input_name
    end

    # TODO: can't use attributes: :attributes but should be able to.
    # Allow a hash to create these these things?
    inputs type: :attributes,
           element_type_declarations: {
             entity_input_name => entity_class,
             element_to_remove: association_type.target_class
           },
           required: [entity_input_name, :element_to_remove]

    result association_type.target_class

    to_load entity_input_name

    def execute
      remove_record_from_collection

      element_to_remove
    end

    attr_accessor :new_collection

    def remove_record_from_collection
      collection = DataPath.value_at(path_to_collection, record)

      self.new_collection = collection.reject { |element| element == element_to_remove }

      if collection == new_collection
        add_runtime_error(
          self.class::ElementNotInCollectionError.new(
            message: "Element not in collection so can't remove it.",
            context: {} # TODO: make this the default
          )
        )
      end

      DataPath.set_value_at(record, new_collection, path_to_collection)
    end

    def record
      inputs[entity_input_name]
    end
  end
end

#create_update_aggregate_commandObject



127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
# File 'foobara-autocrud-0.0.1/src/create_commands.rb', line 127

def create_update_aggregate_command
  entity_class = self.entity_class
  domain = entity_class.domain
  command_name = [*domain.scoped_full_path,
                  "Update#{entity_class.entity_type.scoped_short_name}Aggregate"].join("::")

  Util.make_class command_name, Foobara::Command do
    define_method :entity_class do
      entity_class
    end

    # TODO: does this work with User instead of :User ?
    # We can't come up with a cleaner way to do this?
    inputs entity_class.attributes_for_aggregate_update
    result entity_class # seems like we should just use nil?

    def execute
      update_record

      record
    end

    attr_accessor :record

    def load_records
      self.record = entity_class.load(id)
    end

    def update_record
      record.update_aggregate(inputs)
    end
  end
end

#create_update_atom_commandObject

rubocop:disable Lint/NestedMethodDefinition



92
93
94
95
96
97
98
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
# File 'foobara-autocrud-0.0.1/src/create_commands.rb', line 92

def create_update_atom_command
  entity_class = self.entity_class
  domain = entity_class.domain
  command_name = [*domain.scoped_full_path, "Update#{entity_class.entity_type.scoped_short_name}Atom"].join("::")

  Util.make_class command_name, Foobara::Command do
    define_method :entity_class do
      entity_class
    end

    # TODO: make this work with just inputs :UserAttributesForAtomUpdate
    # Should this be moved to this project instead of living in entities?
    inputs entity_class.attributes_for_atom_update
    result entity_class # seems like we should just use nil?

    def execute
      update_record

      record
    end

    attr_accessor :record

    def load_records
      self.record = entity_class.load(id)
    end

    def update_record
      inputs.each_pair do |attribute_name, value|
        record.write_attribute(attribute_name, value)
      end
    end
  end
end

#executeObject



57
58
59
60
61
# File 'foobara-autocrud-0.0.1/src/create_commands.rb', line 57

def execute
  create_commands

  created_commands
end