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.



438
439
440
441
# File 'backend/app/model/ASModel_crud.rb', line 438

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

#associations_to_eagerly_loadObject



503
504
505
506
507
# File 'backend/app/model/ASModel_crud.rb', line 503

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

#corresponds_to(jsonmodel) ⇒ Object



471
472
473
474
475
476
477
478
479
480
481
482
483
484
# File 'backend/app/model/ASModel_crud.rb', line 471

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.



322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
# File 'backend/app/model/ASModel_crud.rb', line 322

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

  if model_scope == :repository && values["repo_id"] == Repository.global_repo_id &&
     !allowed_in_global_repo

    raise BadParamsException.new("The global repository cannot contain archival records")
  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
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.



417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
# File 'backend/app/model/ASModel_crud.rb', line 417

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.



445
446
447
# File 'backend/app/model/ASModel_crud.rb', line 445

def enclosing_associations
  @enclosing_associations || []
end

#fire_update(json, sequel_obj) ⇒ Object

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



356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
# File 'backend/app/model/ASModel_crud.rb', line 356

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



450
451
452
453
454
455
456
457
# File 'backend/app/model/ASModel_crud.rb', line 450

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



460
461
462
463
464
465
466
467
468
# File 'backend/app/model/ASModel_crud.rb', line 460

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



538
539
540
# File 'backend/app/model/ASModel_crud.rb', line 538

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)


488
489
490
# File 'backend/app/model/ASModel_crud.rb', line 488

def has_jsonmodel?
  !@jsonmodel.nil?
end

#high_priority?Boolean

Returns:

  • (Boolean)


350
351
352
# File 'backend/app/model/ASModel_crud.rb', line 350

def high_priority?
  RequestContext.get(:is_high_priority)
end

#is_relationship?Boolean

Returns:

  • (Boolean)


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

def is_relationship?
  false
end

#my_jsonmodel(ok_if_missing = false) ⇒ Object

Return the JSONModel class that maps to this backend model



494
495
496
# File 'backend/app/model/ASModel_crud.rb', line 494

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



384
385
386
# File 'backend/app/model/ASModel_crud.rb', line 384

def nested_records
  @nested_records ||= []
end

#repo_unique_constraint(property, constraints) ⇒ Object



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

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

#repo_unique_constraintsObject



558
559
560
# File 'backend/app/model/ASModel_crud.rb', line 558

def repo_unique_constraints
  Array(@repo_unique_constraints)
end

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



499
500
501
# File 'backend/app/model/ASModel_crud.rb', line 499

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

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



510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
# File 'backend/app/model/ASModel_crud.rb', line 510

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



550
551
552
553
554
555
# File 'backend/app/model/ASModel_crud.rb', line 550

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



543
544
545
546
547
# File 'backend/app/model/ASModel_crud.rb', line 543

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