Module: ASModel::CRUD::ClassMethods

Defined in:
backend/app/model/ASModel_crud.rb

Instance Method Summary collapse

Instance Method Details

#add_enclosing_association(association) ⇒ Object

Record the association of the record that encloses this one. For example, an Archival Object encloses an Instance record because an Instance is a nested record of an Archival Object.



464
465
466
467
# File 'backend/app/model/ASModel_crud.rb', line 464

def add_enclosing_association(association)
  @enclosing_associations ||= []
  @enclosing_associations << association
end

#associations_to_eagerly_loadObject



529
530
531
532
533
# File 'backend/app/model/ASModel_crud.rb', line 529

def associations_to_eagerly_load
  # Allow subclasses to force eager loading of certain associations to
  # save SQL queries.
  []
end

#corresponds_to(jsonmodel) ⇒ Object



497
498
499
500
501
502
503
504
505
506
507
508
509
510
# File 'backend/app/model/ASModel_crud.rb', line 497

def corresponds_to(jsonmodel)
  @jsonmodel = jsonmodel

  include(DynamicEnums)

  enums = []
  @jsonmodel.schema['properties'].each do |prop, defn|
    if defn["dynamic_enum"]
      enums << {:property => prop, :uses_enum => [defn['dynamic_enum']]}
    end
  end

  uses_enums(*enums)
end

#create_from_json(json, extra_values = {}) ⇒ Object

Create a new record instance from the JSONModel ‘json’. Also creates any nested record instances that it contains.



353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
# File 'backend/app/model/ASModel_crud.rb', line 353

def create_from_json(json, extra_values = {})
  self.strict_param_setting = false
  values = ASUtils.keys_as_strings(extra_values)

  if model_scope == :repository && !values.has_key?("repo_id")
    values["repo_id"] = active_repository
  end

  values['created_by'] = RequestContext.get(:current_username)

  obj = self.create(prepare_for_db(json.class,
                                   json.to_hash.merge(values)))

  obj.apply_nested_records(json, true)

  fire_update(json, obj)

  obj.refresh
  obj.create_ark_name if AppConfig[:arks_enabled]
  obj
end

#def_nested_record(opts) ⇒ Object

Match a JSONModel object to an existing database association.

This linkage manages records that contain subrecords:

  • When storing a JSON blob in the database, the linkage indicates which parts of the JSON should be plucked out and stored as separate database records (with the appropriate associations)

  • When requesting a record in JSON format, the linkage indicates which associated database records should be pulled back and included in the JSON returned.

For example, this definition from subject.rb:

def_nested_record(:the_property => :terms, :contains_records_of_type => :term, :corresponding_to_association => :term)

Causes an incoming JSONModel(:subject) to have each of the objects in its “terms” array to be coerced into a Sequel model (based on the :terms association) and stored in the database. The provided list of terms are associated with the subject as it is stored, and these replace any previous terms.

The definition also causes Subject.to_jsonmodel(obj) to automatically pull back the list of terms associated with the object and include them in the response.



443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
# File 'backend/app/model/ASModel_crud.rb', line 443

def def_nested_record(opts)
  opts[:association] = self.association_reflection(opts[:corresponding_to_association])
  opts[:jsonmodel] = opts[:contains_records_of_type]
  opts[:json_property] = opts[:the_property]

  opts[:is_array] = true if !opts.has_key?(:is_array)

  # Store our association on the nested record's model so we can walk back
  # the other way.
  ArchivesSpaceService.loaded_hook do
    nested_model = Kernel.const_get(opts[:association][:class_name])
    nested_model.add_enclosing_association(opts[:association])
  end

  nested_records << opts
end

#enclosing_associationsObject

If this is a nested record, return the list of associations that link us back to our parent(s). Top-level records just return an empty list.



471
472
473
# File 'backend/app/model/ASModel_crud.rb', line 471

def enclosing_associations
  @enclosing_associations || []
end

#fire_update(json, sequel_obj) ⇒ Object

(Potentially) notify the real-time indexer that an update is available.



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
# File 'backend/app/model/ASModel_crud.rb', line 382

def fire_update(json, sequel_obj)
  if high_priority?
    model = self

    uri = sequel_obj.uri

    # We don't index records without URIs, so no point digging them out of the database either.
    return unless uri

    record_id = sequel_obj.id
    repo_id = RequestContext.get(:repo_id)

    DB.after_commit do
      RequestContext.open(:repo_id => repo_id) do
        # if the record was created in a transaction that was rolled back
        # then it won't exist after the rollback, so we make sure it's there
        # before trying to fire the update
        record = model.any_repo.filter(:id => record_id).first
        if record
          hash = model.to_jsonmodel(record).to_hash(:trusted)
          RealtimeIndexing.record_update(hash, uri)
        end
      end
    end
  end
end

#get_nested_graphObject



476
477
478
479
480
481
482
483
# File 'backend/app/model/ASModel_crud.rb', line 476

def get_nested_graph
  Hash[nested_records.map {|nested_record|
         model = Kernel.const_get(nested_record[:association][:class_name])
         association = nested_record[:corresponding_to_association]

         [association, model.get_nested_graph]
       }]
end

#get_or_die(id) ⇒ Object



486
487
488
489
490
491
492
493
494
# File 'backend/app/model/ASModel_crud.rb', line 486

def get_or_die(id)
  obj = if self.model_scope == :repository
          self.this_repo[:id => id]
        else
          self[id]
        end

  obj or raise NotFoundException.new("#{self} not found")
end

#handle_delete(ids_to_delete) ⇒ Object



564
565
566
# File 'backend/app/model/ASModel_crud.rb', line 564

def handle_delete(ids_to_delete)
  self.filter(:id => ids_to_delete).delete
end

#has_jsonmodel?Boolean

Does this model have a corresponding JSONModel?

Returns:

  • (Boolean)


514
515
516
# File 'backend/app/model/ASModel_crud.rb', line 514

def has_jsonmodel?
  !@jsonmodel.nil?
end

#high_priority?Boolean

Returns:

  • (Boolean)


376
377
378
# File 'backend/app/model/ASModel_crud.rb', line 376

def high_priority?
  RequestContext.get(:is_high_priority)
end

#is_relationship?Boolean

Returns:

  • (Boolean)


595
596
597
# File 'backend/app/model/ASModel_crud.rb', line 595

def is_relationship?
  false
end

#my_jsonmodel(ok_if_missing = false) ⇒ Object

Return the JSONModel class that maps to this backend model



520
521
522
# File 'backend/app/model/ASModel_crud.rb', line 520

def my_jsonmodel(ok_if_missing = false)
  @jsonmodel or (ok_if_missing ? nil : raise("No corresponding JSONModel set for model #{self.inspect}"))
end

#nested_recordsObject



410
411
412
# File 'backend/app/model/ASModel_crud.rb', line 410

def nested_records
  @nested_records ||= []
end

#repo_unique_constraint(property, constraints) ⇒ Object



589
590
591
592
# File 'backend/app/model/ASModel_crud.rb', line 589

def repo_unique_constraint(property, constraints)
  @repo_unique_constraints ||= []
  @repo_unique_constraints << constraints.merge(:property => property)
end

#repo_unique_constraintsObject



584
585
586
# File 'backend/app/model/ASModel_crud.rb', line 584

def repo_unique_constraints
  Array(@repo_unique_constraints)
end

#sequel_to_jsonmodel(objs, opts = {}) ⇒ Object



525
526
527
# File 'backend/app/model/ASModel_crud.rb', line 525

def sequel_to_jsonmodel(objs, opts = {})
  NestedRecordResolver.new(nested_records, objs).resolve
end

#to_jsonmodel(obj, opts = {}) ⇒ Object



536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
# File 'backend/app/model/ASModel_crud.rb', line 536

def to_jsonmodel(obj, opts = {})
  is_id_query     = obj.is_a?(Integer)
  is_string_query = obj.is_a?(String) && opts[:query]

  if is_id_query || is_string_query
    ds = if self.model_scope == :repository
           self.this_repo
         else
           self
         end

    # An ID.  Get the Sequel row for it.
    if is_id_query
      obj = ds.eager(get_nested_graph).filter(:id => obj).all[0]

    # If we have a string and query option, attempt to look up by querying string value against column name.
    elsif is_string_query
      obj = ds.eager(get_nested_graph).filter(opts[:query].to_sym => obj).all[0]
    end

    raise NotFoundException.new("#{self} not found") unless obj
    obj.eagerly_load!
  end

  sequel_to_jsonmodel([obj], opts)[0]
end

#update_mtime_for_ids(ids) ⇒ Object



576
577
578
579
580
581
# File 'backend/app/model/ASModel_crud.rb', line 576

def update_mtime_for_ids(ids)
  now = Time.now
  ids.each_slice(1000) do |subset|
    self.dataset.filter(:id => subset).update(:system_mtime => now)
  end
end

#update_mtime_for_repo_id(repo_id) ⇒ Object



569
570
571
572
573
# File 'backend/app/model/ASModel_crud.rb', line 569

def update_mtime_for_repo_id(repo_id)
  if model_scope == :repository
    self.dataset.filter(:repo_id => repo_id).update(:system_mtime => Time.now) if self.dataset.columns.include? :repo_id
  end
end