Module: Familia::Features::Relationships::Querying::InstanceMethods

Defined in:
lib/familia/features/relationships/querying.rb

Overview

Instance methods for querying relationships

Instance Method Summary collapse

Instance Method Details

#accessible_collections(min_permission: nil) ⇒ Array<Hash>

Find all collections this object appears in with specific permissions

Parameters:

  • min_permission (Symbol) (defaults to: nil)

    Minimum required permission

Returns:

  • (Array<Hash>)

    Collections this object is a member of



389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
# File 'lib/familia/features/relationships/querying.rb', line 389

def accessible_collections(min_permission: nil)
  collections = []

  # Check tracking relationships
  if self.class.respond_to?(:tracking_relationships)
    collections.concat(find_tracking_collections(min_permission))
  end

  # Check membership relationships
  if self.class.respond_to?(:membership_relationships)
    collections.concat(find_membership_collections(min_permission))
  end

  collections
end

#find_similar_objects(min_shared_collections: 1) ⇒ Array<Hash>

Find similar objects based on shared collection membership

Parameters:

  • min_shared_collections (Integer) (defaults to: 1)

    Minimum shared collections

Returns:

  • (Array<Hash>)

    Similar objects with similarity scores



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
# File 'lib/familia/features/relationships/querying.rb', line 446

def find_similar_objects(min_shared_collections: 1)
  my_collections = accessible_collections
  return [] if my_collections.empty?

  similar_objects = {}

  my_collections.each do |collection_info|
    collection_key = collection_info[:key]

    # Get all members of this collection
    other_members = dbclient.zrange(collection_key, 0, -1)
    other_members.delete(identifier) # Remove self

    other_members.each do |other_identifier|
      similar_objects[other_identifier] ||= {
        shared_collections: 0,
        collections: [],
        identifier: other_identifier
      }
      similar_objects[other_identifier][:shared_collections] += 1
      similar_objects[other_identifier][:collections] << collection_info
    end
  end

  # Filter by minimum shared collections and calculate similarity
  results = similar_objects.values
                           .select { |obj| obj[:shared_collections] >= min_shared_collections }

  results.each do |obj|
    obj[:similarity] = obj[:shared_collections].to_f / my_collections.length
  end

  results.sort_by { |obj| -obj[:similarity] }
end

#permission_in_collection(owner, collection_name) ⇒ Integer?

Get permission bits in a specific collection

Parameters:

  • owner (Object)

    Collection owner

  • collection_name (Symbol)

    Collection name

Returns:

  • (Integer, nil)

    Permission bits or nil if not a member



410
411
412
413
414
415
416
417
418
# File 'lib/familia/features/relationships/querying.rb', line 410

def permission_in_collection(owner, collection_name)
  collection_key = "#{owner.class.name.downcase}:#{owner.identifier}:#{collection_name}"
  score = dbclient.zscore(collection_key, identifier)

  return nil unless score

  decoded = permission_decode(score)
  decoded[:permissions]
end

#permission_in_collection?(owner, collection_name, required_permission) ⇒ Boolean

Check if this object has specific permission in a collection

Parameters:

  • owner (Object)

    Collection owner

  • collection_name (Symbol)

    Collection name

  • required_permission (Symbol)

    Required permission

Returns:

  • (Boolean)

    True if object has required permission



426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
# File 'lib/familia/features/relationships/querying.rb', line 426

def permission_in_collection?(owner, collection_name, required_permission)
  current_bits = permission_in_collection(owner, collection_name)
  return false if current_bits.nil? # Not in collection

  begin
    required_bits = ScoreEncoding.permission_level_value(required_permission)
  rescue ArgumentError
    # Invalid permission symbol - deny access
    return false
  end

  # Check if current permissions include the required permission using bitwise AND
  # Note: 0 bits means exists in collection but no permissions
  (current_bits & required_bits) == required_bits
end