Class | ArsModels::Entry |
In: |
lib/ars_models/entry.rb
|
Parent: | BaseWithContext |
Ruby wrapper class for the java ArsEntry object. Instances of Entry represent a single Ars record.
ars_entry | [RW] | TODO: Document ArsModels::Entry#ars_entry attribute |
context | [RW] | TODO: Document ArsModels::Entry#context attribute |
field_values | [RW] | TODO: Document ArsModels::Entry#field_values attribute |
form | [RW] | TODO: Document ArsModels::Entry#form attribute |
id | [RW] | TODO: Document ArsModels::Entry#id attribute |
messages | [RW] | TODO: Document ArsModels::Entry#messages attribute |
modified_attributes | [RW] | TODO: Document ArsModels::Entry#modified_attributes attribute |
TODO: Document ArsModels::Entry.create!
# File lib/ars_models/entry.rb, line 34 34: def self.create!(options={}) 35: # FIXME: This should not be save! directly 36: save!(options) 37: end
Delete operates with two different selection approaches:
Delete All: This will attempt to delete all the records matching the passed conditions and return an array including Entry objects for successfully deleted records and Exceptions::ModelException objects for any records that encountered an error when being deleted.
Delete By ID: This can either be a specific id (‘000000000000001’), a list of ids (‘000000000000001’, ‘000000000000005’, ‘000000000000006’), or an array of ids ([‘000000000000001’, ‘000000000000005’, ‘000000000000006’]). If a single id is passed, the single deleted matching record will be returned (or an Exceptions::ModelException will be raised if an error was encountered). If multiple ids are passed, an array including Entry objects for successfully deleted records and Exceptions::ModelException objects for any records that encountered an error when being deleted will be returned.
Anytime delete is called with the :all operation, or passed multiple IDs to delete, additional helper methods are available for the resulting array. The successes method will return a hash of results index keys mapped to the corresponding successfuly deleted entry objects, and the failures method will return a hash of results index keys mapped to the corresponding unsucessfuly entry deletion exceptions.
# Preamble context = Context.new(:username => 'Demo', :password => '', :server => '127.0.0.1', :port => '0') group_form = Form.find('Group') # Delete all non-system groups results = Entry.delete(:all, :context => context, :form => group_form, :conditions => ["? > 7", 'Group ID']) # Display the results puts "Successes: " results.successes.each do {|results_index, entry| puts " #{entry.id}"} puts "Failures: " results.failures.each do {|results_index, exception| puts " #{exception.to_s}"} # Delete a single group entry (Administrators) by id Entry.delete(000000000000001, :context => context, :form => group_form) # Delete multiple group entries (Administrators, Public) by id results = Entry.delete(000000000000001, 000000000000006, :context => context, :form => group_form) results = Entry.delete([000000000000001,000000000000006], :context => context, :form => group_form) # Display the results puts "Successes: " results.successes.each do {|results_index, entry| puts " #{entry.id}"} puts "Failures: " results.failures.each do {|results_index, exception| puts " #{exception.to_s}"}
# File lib/ars_models/entry.rb, line 117 117: def self.delete!(*args) 118: # TODO: Abstraction - Clean up and document the delete logic chain 119: # TODO: Feature Completion - Test paged deletions? (ArsModels::Entry.delete) 120: # TODO: Feature Completion - include_attachments? (ArsModels::Entry.delete) 121: # TODO: Feature Completion - Messages triggered by deletes 122: 123: # Pop the last argument if it is an options hash 124: options = args.last.is_a?(::Hash) ? args.pop.clone : {} 125: 126: # Default the context if this class was created with a context instance 127: options[:context] ||= context if context 128: 129: # Validate that the options are valid 130: validate_options(options, 131: :required => [:context, :form], 132: :optional => [:conditions, :fields] 133: ) 134: 135: # Build the array of requested field ids 136: field_ids = build_field_ids(options.delete(:fields), options[:form]) 137: 138: # Call the appropriate find method 139: if args.first == :all 140: # Build the qualification information 141: options[:qualification], options[:qualification_field_ids] = build_qualification(options.delete(:conditions), options[:form]) 142: 143: # Make the JAPI models call to find all of the matching results 144: ars_find_results = ArsEntry.findAll( 145: options[:context].ars_context, 146: options[:form].ars_form, 147: options[:qualification], 148: options[:qualification_field_ids].to_java(:Long), 149: field_ids.nil? ? nil : field_ids.to_java(:Long) 150: ) 151: 152: # Declare the requried result objects 153: results, successes, failures = [], {}, {} 154: 155: # Collect the results, converting them to Entry or Exception objects 156: ars_find_results.collect do |ars_result| 157: begin 158: # Call the japi delete method 159: ars_result.delete(options[:context].ars_context) 160: # Build a new Entry from the japi object 161: result = new(ars_result, :context => options[:context], :form => options[:form]) 162: # Add it to the successes hash 163: successes[results.length] = result 164: # Add it to the results array 165: results << result 166: rescue StandardError => exception 167: # Process the exception 168: exception = Exceptions::InternalError.process(exception) 169: # Add the exception to the failures hash 170: failures[results.length] = exception 171: # Add the exception to the results array 172: results << exception 173: end 174: end 175: 176: # Add the successes method to the results array 177: results_metaclass = class << results; self; end 178: results_metaclass.instance_eval do 179: define_method(:successes) {successes} 180: define_method(:failures) {failures} 181: end 182: 183: # Return the results 184: results 185: # If this is no an :all, :first, :last, :rand, or :single search 186: else 187: # Build the list of ids 188: ids = args.flatten.collect {|record| record.is_a?(ArsModels::Entry) ? record.id : record} 189: 190: # If there were no entries, return an empty array 191: if args.length == 0 192: raise ArgumentError.new('Missing arguments specifying records to delete.') 193: # If there was one entry, try to delete it 194: elsif args.length == 1 && !args.first.is_a?(::Array) 195: begin 196: # Call the japi delete method 197: ars_result = ArsEntry.delete( 198: options[:context].ars_context, 199: options[:form].ars_form, 200: ids.first, 201: field_ids.nil? ? nil : field_ids.to_java('Long''Long') 202: ) 203: # Build a new Entry from the japi object 204: result = new(ars_result, :context => options[:context], :form => options[:form]) 205: rescue StandardError => exception 206: # Process the exception 207: raise Exceptions::InternalError.process(exception) 208: end 209: # If multiple entries were deleted 210: else 211: # Declare the requried result objects 212: results, successes, failures = [], {}, {} 213: 214: # Collect the results, converting them to Entry or Exception objects 215: ids.collect do |id| 216: begin 217: # Call the japi delete method 218: ars_result = ArsEntry.delete( 219: options[:context].ars_context, 220: options[:form].ars_form, 221: id, 222: field_ids.nil? ? nil : field_ids.to_java('Long''Long') 223: ) 224: # Build a new Entry from the japi object 225: result = new(ars_result, :context => options[:context], :form => options[:form]) 226: # Add it to the successes hash 227: successes[results.length] = result 228: # Add it to the results array 229: results << result 230: rescue StandardError => exception 231: # Process the exception 232: exception = Exceptions::InternalError.process(exception) 233: # Add the exception to the failures hash 234: failures[results.length] = exception 235: # Add the exception to the results array 236: results << exception 237: end 238: end 239: 240: # Add the successes method to the results array 241: results_metaclass = class << results; self; end 242: results_metaclass.instance_eval do 243: define_method(:successes) {successes} 244: define_method(:failures) {failures} 245: end 246: 247: # Return the results 248: results 249: end 250: end 251: end
Find operates with four different retrieval approaches:
Find All: This will return all the records matched by the options used. If no records are found, an empty array is returned.
Find By ID: This can either be a specific id (‘000000000000001’), a list of ids (‘000000000000001’, ‘000000000000005’, ‘000000000000006’), or an array of ids ([‘000000000000001’, ‘000000000000005’, ‘000000000000006’]). If a single id is passed, the single matched record will be returned, or nil if it is not found. If multiple ids are passed, an array of records will be returned. Entry ids not found will result in a nil object.
Find By Position: There are three options for finding an entry by position.
Find Single: This will return a single record matched by the options used. If a matching record is not found, nil is returned. If more than one record is found an exception is raised. Find single is most frequently used to retrieve a record by GUID or other non-id unique identifier.
When the find all operation is used, the resulting array is patched to include pagination meta-data. The following method calls are available for the resulting array:
# Preamble context = Context.new(:username => 'Demo', :password => '', :server => '127.0.0.1', :port => '0') group_form = Form.find('Group') # Find all system groups Entry.find(:all, :context => context, :form => group_form, :conditions => ["? <= 7", 'Group ID']) # Find single group entry (Administrators) by id Entry.find(000000000000001, :context => context, :form => group_form) # Find multiple group entries (Administrators, Public) by id Entry.find(000000000000001, 000000000000006, :context => context, :form => group_form) Entry.find([000000000000001,000000000000006], :context => context, :form => group_form) # Find the first group alphabetically Entry.find(:first, :context => context, :form => group_form, :order => ['Group Name']) # Find the most recently created group Entry.find(:last, :context => context, :form => group_form, :order => ['Create Date']) # Find a random group Entry.find(:rand, :context => context, :form => group_form) # Find single group entry with the provided unique identifier Entry.find(:single, :context => context, :form => group_form, :conditions => {'Unique Identifier' => "AG0c29df58dc1rCgRQAGMuAAY_zD"})
# File lib/ars_models/entry.rb, line 358 358: def self.find(*args) 359: # TODO: Abstraction - Clean up and document the find logic chain 360: # TODO: Feature Completion - Test paged deletions? (ArsModels::Entry.find) 361: # TODO: Feature Completion - include_attachments? (ArsModels::Entry.find) 362: 363: begin 364: # Pop the last argument if it is an options hash 365: options = args.last.is_a?(::Hash) ? args.pop.clone : {} 366: 367: # Default the context if this class was created with a context instance 368: options[:context] ||= context if context 369: 370: # Validate that the options are valid 371: validate_options(options, 372: :required => [:context, :form], 373: :optional => [ 374: :conditions, 375: :field_ids, 376: :fields, 377: :include_attachments, 378: :limit, 379: :order, 380: :page 381: ] 382: ) 383: 384: # Default shared options 385: options[:include_attachments] ||= false 386: 387: # Build the array of requested field ids 388: options[:field_ids] = build_field_ids(options.delete(:fields), options[:form]) 389: 390: # Call the appropriate find method 391: if [:all, :first, :last, :rand, :single].include?(args.first) 392: # Default order 393: options[:order] = build_field_ids(options.delete(:order), options[:form]) || options[:form].sort_field_ids 394: 395: # Build the qualification information 396: options[:qualification], options[:qualification_field_ids] = build_qualification(options.delete(:conditions), options[:form]) 397: 398: # Call the corresponding find 399: case args.first 400: when :all then 401: # Validate the options 402: validate_options(options, 403: :required => [ 404: :context, :form, :field_ids, :include_attachments, :qualification, :qualification_field_ids 405: ], 406: :optional => [:limit, :order, :page] 407: ) 408: 409: # Compute the chunk index (which is indexed by 0, where :page is indexed by 1) 410: chunk_index = options[:page] ? (options[:page] - 1) : 0 411: 412: # Get the JAPI results 413: find_result = ArsEntry.findAllWithCount( 414: options[:context].ars_context, 415: options[:form].ars_form, 416: options[:qualification], 417: options[:qualification_field_ids].to_java('Long'), 418: options[:field_ids].nil? ? nil : options[:field_ids].to_java('Long'), 419: options[:order].to_java('Long'), 420: options[:limit], 421: chunk_index, 422: options[:include_attachments] 423: ) 424: 425: # Parse the results to get the entries and the count 426: ars_entries = find_result[0] 427: count = find_result[1] 428: 429: # Convert the JAPI entries into ArsModels entries 430: result = ars_entries.collect do |ars_entry| 431: new(ars_entry, :context => options[:context], :form => options[:form]) 432: end 433: 434: # TODO: Abstraction - Convert this to an include / extend module call so that the results array can be checked via is_a?(ArsModels::Pagination) 435: # Add the pagination helper methods 436: result_metaclass = class << result; self; end 437: result_metaclass.instance_eval do 438: define_method(:total_entries) {count} 439: define_method(:total_pages) {options[:limit] == 0 ? 1 : (count.to_f / options[:limit]).ceil} 440: define_method(:current_page) {chunk_index} 441: define_method(:previous_page) {chunk_index == 0 ? nil : chunk_index} 442: define_method(:next_page) {chunk_index+1 == total_pages ? nil : chunk_index+2} 443: end 444: 445: # Return the result set 446: result 447: when :first, :last then 448: # TODO: Feature Completion - Implement first/last for paging (ArsModels::Entry.find) 449: 450: # Validate the options 451: validate_options(options, 452: :required => [:context, :form], 453: :optional => [:field_ids, :include_attachments, :order, :qualification, :qualification_field_ids] 454: ) 455: 456: # Reverse the order if looking for the last 457: options[:order].collect! {|id| -id} if args.first == :last 458: 459: # Make the JAPI models call 460: entries = ArsEntry.find_all( 461: options[:context].ars_context, 462: options[:form].ars_form, 463: options[:qualification], 464: options[:qualification_field_ids].to_java('Long'), 465: options[:field_ids].nil? ? nil : options[:field_ids].to_java('Long'), 466: options[:order].to_java('Long'), 467: 1 # Set the limit to 1 468: ).to_a 469: 470: # Generate the result 471: case entries.length 472: when 0 then nil 473: when 1 then new(entries.first, :context => options[:context], :form => options[:form]) 474: else raise 'Multiple entries returned for find by position call.' 475: end 476: when :rand then 477: # TODO: Feature Completion - ArsModels::Entry.find(:rand) 478: raise 'Not Implemented' 479: when :single then 480: # Validate the options 481: validate_options(options, 482: :required => [:context, :form], 483: :optional => [ 484: :field_ids, :include_attachments, :order, :qualification, :qualification_field_ids 485: ] 486: ) 487: 488: # Get the JAPI results 489: find_results = ArsEntry.find_all( 490: options[:context].ars_context, 491: options[:form].ars_form, 492: options[:qualification], 493: options[:qualification_field_ids].to_java('Long'), 494: options[:field_ids].nil? ? nil : options[:field_ids].to_java('Long') 495: ) 496: 497: # Generate the result 498: case find_results.length 499: when 0 then nil 500: when 1 then new(find_results[0], :context => options[:context], :form => options[:form]) 501: else raise "More than one result found by 'single' search" 502: end 503: end 504: # If this is no an :all, :first, :last, :rand, or :single search 505: else 506: # Validate the options 507: validate_options(options, 508: :required => [ 509: :context, 510: :form, 511: :field_ids, 512: :include_attachments 513: ] 514: ) 515: 516: # Convert the list of arguments to an array of Java Strings 517: ids = args.to_java(:string) 518: 519: # Get the JAPI results 520: find_results = ArsEntry.find_all( 521: options[:context].ars_context, 522: options[:form].ars_form, 523: ids, 524: options[:field_ids].nil? ? nil : options[:field_ids].to_java('Long') 525: ) 526: 527: # Convert the JAPI entries into ArsModels entries 528: results = find_results.collect do |ars_entry| 529: ars_entry ? new(ars_entry, :context => options[:context], :form => options[:form]) : nil 530: end 531: 532: # If there was only one entry requested, return the single result, 533: # otherwise return the result array 534: ids.length == 1 && find_results.length == 1 ? results.first : results 535: end 536: rescue NativeException => exception 537: raise Exceptions::ModelException.new(exception.cause) 538: end 539: end
TODO: Document ArsModels::Entry initializer
# File lib/ars_models/entry.rb, line 25 25: def initialize(*args) 26: super(*args) 27: end
TODO: Document ArsModels::Entry.update!
# File lib/ars_models/entry.rb, line 542 542: def self.update!(*args) 543: # FIXME: This should probably not be save! directly 544: # TODO: Enhancement - Implement update!(:single) 545: save!(*args) 546: end
TODO: Document ArsModels::Form#delete!
# File lib/ars_models/entry.rb, line 580 580: def delete!(options={}) 581: # Check for bad options 582: validate_options(options, :optional => [:context, :fields]) 583: 584: # Define the default options 585: default_options = {} 586: default_options[:context] = context if context 587: default_options[:form] = form 588: default_options[:fields] = field_value_ids 589: 590: # Delete this instance 591: self.class.delete!(self.id, default_options.merge(options)) 592: end
TODO: Document ArsModels::Form#field_value_ids
# File lib/ars_models/entry.rb, line 628 628: def field_value_ids 629: @ars_entry.field_value_ids.to_a 630: end
TODO: Document ArsModels::Entry#get_field_value
# File lib/ars_models/entry.rb, line 553 553: def get_field_value(attribute) 554: raise 'Unable to process field value without form definition' unless form 555: field = form.field_for(attribute) 556: field_id = field.id 557: raise "Unable to retrieve field id for key '#{attribute.inspect}' (#{attribute.class.name})." unless field_id 558: begin 559: value = @ars_entry.get_field_value(field_id) 560: rescue StandardError => error 561: raise Exceptions::InternalError.process(error) 562: end 563: FieldValue.to_ruby(value, :field_id => field_id, :form => form, :entry => self) if value 564: end
TODO: Document ArsModels::Form#save!
# File lib/ars_models/entry.rb, line 610 610: def save!(options={}) 611: # Check for bad options 612: validate_options(options, :optional => [:context, :field_values, :fields, :field_ids, :form]) 613: 614: # Raise an exception if the form specified is not the correct form 615: raise "Conflicting forms" if (form && options[:form]) && form.name != options[:form].name 616: 617: # Define the default options 618: default_options = {} 619: default_options[:context] = context if context 620: default_options[:form] = form 621: default_options[:fields] = field_value_ids 622: 623: # Delete this instance 624: self.class.save!(self, default_options.merge(options)) 625: end
TODO: Document ArsModels::Entry#set_field_value
# File lib/ars_models/entry.rb, line 568 568: def set_field_value(attribute, value) 569: raise 'Unable to process field value without form definition' unless form 570: field = form.field_for(attribute) 571: raise "Unable to retrieve field id for key '#{attribute.inspect}' (#{attribute.class.name})." unless field.id 572: new_value = FieldValue.to_java(field, value, @ars_entry.get_field_value(field.id)) 573: @ars_entry.set_field_value(field.id, new_value) 574: @modified_attributes.nil? ? @modified_attributes = {field.id => value} : @modified_attributes[field.id] = value 575: self 576: end
TODO: Document ArsModels::Form#to_xml
# File lib/ars_models/entry.rb, line 657 657: def to_xml 658: # Call the java method 659: @ars_entry.to_xml_string 660: end
TODO: Document ArsModels::Form#update_attributes!
# File lib/ars_models/entry.rb, line 595 595: def update_attributes!(attributes, options={}) 596: # Check for bad options 597: validate_options(options, :optional => [:context, :fields]) 598: 599: # Define the default options 600: default_options = {} 601: default_options[:context] = context if context 602: default_options[:form] = form 603: default_options[:fields] = field_value_ids 604: 605: # Save the update 606: self.class.save!(self, default_options.merge(options).merge(:field_values => attributes)) 607: end