Module: Upkeep::Dependencies

Defined in:
lib/upkeep/dependencies.rb

Defined Under Namespace

Classes: ActiveRecordAttribute, ActiveRecordCollection, ActiveRecordQuery, Base, CookieValue, CurrentAttribute, Identity, RequestValue, Restored, SessionValue, Unknown, WardenUser

Class Method Summary collapse

Class Method Details

.canonical_identity(value) ⇒ Object



516
517
518
519
520
521
522
523
# File 'lib/upkeep/dependencies.rb', line 516

def canonical_identity(value)
  case value
  when nil, true, false, Numeric, String, Symbol
    value
  else
    model_identity(value) || private_fingerprint(value)
  end
end

.deployment_stable_request?(dependency) ⇒ Boolean

Returns:

  • (Boolean)


534
535
536
537
538
539
# File 'lib/upkeep/dependencies.rb', line 534

def deployment_stable_request?(dependency)
  return false unless dependency.identity?
  return false unless dependency.source.to_s == "request"

  RequestValue::DEPLOYMENT_STABLE_KEYS.include?(dependency.key.fetch(:key).to_s)
end

.from_h(snapshot) ⇒ Object



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
# File 'lib/upkeep/dependencies.rb', line 454

def from_h(snapshot)
  snapshot = symbolize_keys(snapshot)
  source = snapshot.fetch(:source)
  key = symbolize_keys(snapshot.fetch(:key))
   = symbolize_keys(snapshot.fetch(:metadata))

  case source.to_sym
  when :active_record_attribute
    ActiveRecordAttribute.new(
      table: key.fetch(:table),
      id: key.fetch(:id),
      attribute: key.fetch(:attribute),
      model: [:model],
      scope: key[:scope]
    )
  when :active_record_collection, :active_record_query
    dependency_class = source.to_sym == :active_record_query ? ActiveRecordQuery : ActiveRecordCollection
    dependency_class.new(
      primary_table: .fetch(:primary_table),
      table_columns: .fetch(:table_columns),
      coverage: .fetch(:coverage),
      sql: .fetch(:sql),
      predicates: .fetch(:predicates)
    )
  else
    if snapshot.fetch(:visibility).to_sym == :identity_bound
      Identity.new(
        source: source,
        key: key.fetch(:key),
        value: key.fetch(:value),
        metadata: 
      )
    else
      Restored.new(
        source: source,
        key: key,
        metadata: ,
        visibility: snapshot.fetch(:visibility),
        precision: snapshot.fetch(:precision)
      )
    end
  end
end

.identity_absent_for?(dependency, name) ⇒ Boolean

Returns:

  • (Boolean)


541
542
543
544
545
546
547
# File 'lib/upkeep/dependencies.rb', line 541

def identity_absent_for?(dependency, name)
  absent_by_name = (dependency, :identity_absent_by_name) || {}
  absent_by_name = absent_by_name.transform_keys(&:to_s) if absent_by_name.respond_to?(:transform_keys)
  return absent_by_name.fetch(name.to_s) if absent_by_name.key?(name.to_s)

  !partitioning_identity?(dependency)
end

.metadata_value(dependency, key) ⇒ Object



553
554
555
556
557
558
559
560
561
# File 'lib/upkeep/dependencies.rb', line 553

def (dependency, key)
  return unless dependency.respond_to?(:metadata)

  if dependency..key?(key)
    dependency..fetch(key)
  elsif dependency..key?(key.to_s)
    dependency..fetch(key.to_s)
  end
end

.model_identity(value) ⇒ Object



498
499
500
501
502
503
504
# File 'lib/upkeep/dependencies.rb', line 498

def model_identity(value)
  return nil unless value

  if value.respond_to?(:id) && value.class.respond_to?(:name)
    { model: value.class.name, id: value.id }
  end
end

.model_metadata(value) ⇒ Object



506
507
508
509
510
511
512
513
514
# File 'lib/upkeep/dependencies.rb', line 506

def (value)
  return {} unless value

  {
    model: value.class.name,
    table: value.class.respond_to?(:table_name) ? value.class.table_name : nil,
    id: value.respond_to?(:id) ? value.id : nil
  }.compact
end

.nil_identity?(dependency) ⇒ Boolean

Returns:

  • (Boolean)


549
550
551
# File 'lib/upkeep/dependencies.rb', line 549

def nil_identity?(dependency)
  dependency.respond_to?(:nil_identity?) && dependency.nil_identity?
end

.partitioning_identity?(dependency) ⇒ Boolean

Returns:

  • (Boolean)


525
526
527
528
529
530
531
532
# File 'lib/upkeep/dependencies.rb', line 525

def partitioning_identity?(dependency)
  return false unless dependency.identity?

  flag = (dependency, :partitioning_identity)
  return flag if [true, false].include?(flag)

  !nil_identity?(dependency)
end

.private_fingerprint(value) ⇒ Object



563
564
565
# File 'lib/upkeep/dependencies.rb', line 563

def private_fingerprint(value)
  Digest::SHA256.hexdigest(JSON.generate(private_fingerprint_payload(value)))[0, 16]
end

.private_fingerprint_payload(value) ⇒ Object



567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
# File 'lib/upkeep/dependencies.rb', line 567

def private_fingerprint_payload(value)
  case value
  when nil, true, false, Numeric, String
    [value.class.name, value]
  when Symbol
    ["Symbol", value.to_s]
  when Array
    ["Array", value.map { |item| private_fingerprint_payload(item) }]
  when Hash
    entries = value.keys.sort_by { |key| JSON.generate(private_fingerprint_payload(key)) }.map do |key|
      [private_fingerprint_payload(key), private_fingerprint_payload(value.fetch(key))]
    end
    ["Hash", entries]
  else
    identity = model_identity(value)
    identity ? ["Model", identity] : ["Object", value.class.name, value.inspect]
  end
end

.symbolize_keys(value) ⇒ Object



586
587
588
589
590
591
592
593
594
595
596
597
598
# File 'lib/upkeep/dependencies.rb', line 586

def symbolize_keys(value)
  case value
  when Hash
    value.each_with_object({}) do |(key, nested_value), result|
      normalized_key = key.respond_to?(:to_sym) ? key.to_sym : key
      result[normalized_key] = symbolize_keys(nested_value)
    end
  when Array
    value.map { |nested_value| symbolize_keys(nested_value) }
  else
    value
  end
end