Module: ActiveRecordExtended::LtreeQueryMethods

Defined in:
lib/active_record_extended/ltree_query_methods.rb

Overview

Mixed into ActiveRecord::QueryMethods to add where.ltree_contains,
where.ltree_depth, and the related ltree-aware select / order helpers
described in the file header.

Instance Method Summary collapse

Instance Method Details

#ltree_contains(column, ids, array: true) ⇒ Object

ltree contains check - does the path contain a specific subpath anywhere?
Uses the index() function which has no simple Arel equivalent.

Example:
ProductLine.where.ltree_contains(:ltree_path_ids, '102', array: false)
ViewProductCatalog.where.ltree_contains(:all_pl_paths_ids, [1, 2])
CatalogItem.with_item.where.ltree_contains('items.all_pl_paths_ids', [58, 59])

Parameters:

  • column (Symbol, String)

    The ltree or ltree[] column (can include table: 'items.all_pl_paths_ids')

  • ids (String, Integer, Array)

    The ID(s) to find in the path

  • array (Boolean) (defaults to: true)

    Whether the column is an ltree[] (default: true)



81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/active_record_extended/ltree_query_methods.rb', line 81

def ltree_contains(column, ids, array: true)
  ids = [ids].flatten.compact.filter_map { |id| Integer(id, exception: false) }
  return none_query if ids.empty?

  col = column.to_s.include?('.') ? column.to_s : "#{table_name}.#{column}"

  if array
    @scope.where(
      "EXISTS (SELECT 1 FROM unnest(#{col}) AS p, unnest(ARRAY[?]::ltree[]) AS id WHERE index(p, id) >= 0)",
      ids.map(&:to_s)
    )
  else
    @scope.where(
      "EXISTS (SELECT 1 FROM unnest(ARRAY[?]::ltree[]) AS id WHERE index(#{col}, id) >= 0)",
      ids.map(&:to_s)
    )
  end
end

#ltree_depth(column, depth, operator = :eq) ⇒ Object

ltree depth check using nlevel()

Example:
ProductCategory.where.ltree_depth(:ltree_path_ids, 2) # depth = 2
ProductCategory.where.ltree_depth(:ltree_path_ids, 2, :gt) # depth > 2

Parameters:

  • column (Symbol)

    The ltree column

  • depth (Integer)

    The depth to check

  • operator (Symbol) (defaults to: :eq)

    Comparison operator (:eq, :gt, :gte, :lt, :lte)



110
111
112
113
114
115
116
117
118
119
120
121
# File 'lib/active_record_extended/ltree_query_methods.rb', line 110

def ltree_depth(column, depth, operator = :eq)
  op = case operator
       when :eq then '='
       when :gt then '>'
       when :gte then '>='
       when :lt then '<'
       when :lte then '<='
       else raise ArgumentError, "Invalid operator: #{operator}. Use :eq, :gt, :gte, :lt, :lte"
       end

  @scope.where("nlevel(#{table_name}.#{column}) #{op} ?", depth)
end