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



385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
# File 'lib/familia/features/relationships/querying.rb', line 385

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



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

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



406
407
408
409
410
411
412
413
414
# File 'lib/familia/features/relationships/querying.rb', line 406

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



422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
# File 'lib/familia/features/relationships/querying.rb', line 422

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