Module: Arfi::Commands::FunctionsCandidates

Included in:
Functions
Defined in:
lib/arfi/commands/functions_candidates.rb,
sig/lib/arfi/commands/functions_candidates.rbs

Overview

Candidate discovery helpers for Functions.

Constant Summary collapse

DEFAULT_SCHEMA =

Returns:

  • ("public")

Instance Method Summary collapse

Instance Method Details

#adapter_candidates(adapter_root, adapter) ⇒ Array<Arfi::Commands::candidate>

Collect function candidates from an adapter-specific directory (legacy + explicit public).

Parameters:

  • adapter_root (Pathname) —

    Adapter root directory (e.g. db/functions/postgresql)

  • adapter (String) —

    Database adapter name

Returns:

  • (Array<Arfi::Commands::candidate>)


81
82
83
84
85
86
87
88
# File 'lib/arfi/commands/functions_candidates.rb', line 81

def adapter_candidates(adapter_root, adapter)
  candidates = [] # steep:ignore
  candidates.concat collect_candidates(glob: adapter_root.join('*.sql'), schema: DEFAULT_SCHEMA,
                                       source: adapter, origin: 'legacy', priority: 8)
  candidates.concat collect_candidates(glob: adapter_root.join(DEFAULT_SCHEMA, '*.sql'),
                                       schema: DEFAULT_SCHEMA, source: adapter, origin: 'explicit', priority: 9)
  candidates
end

#build_resolved_rows(by_key) ⇒ Array<Hash<Symbol, Object>>

Build the final resolved rows by picking the highest-priority candidate per key.

Parameters:

  • by_key (Hash<String, Array<Arfi::Commands::candidate>>) —

    Candidates grouped by key

Returns:

  • (Array<Hash<Symbol, Object>>)


44
45
46
47
48
# File 'lib/arfi/commands/functions_candidates.rb', line 44

def build_resolved_rows(by_key)
  by_key.keys.sort.flat_map do |key|
    resolve_key_group(by_key[key])
  end.compact
end

#collect_all_candidates(root, adapter) ⇒ Array<Arfi::Commands::candidate>

Collect all function candidates from generic, adapter, and (for PostgreSQL) schema directories.

Parameters:

  • root (Pathname) —

    Project root directory (Rails.root/db/functions)

  • adapter (String) —

    Database adapter name (postgresql, mysql, trilogy)

Returns:

  • (Array<Arfi::Commands::candidate>)


15
16
17
18
19
20
21
22
23
# File 'lib/arfi/commands/functions_candidates.rb', line 15

def collect_all_candidates(root, adapter)
  candidates = generic_candidates(root)
  adapter_root = root.join(adapter)
  return candidates unless adapter_root.directory?

  candidates.concat adapter_candidates(adapter_root, adapter)
  candidates.concat collect_postgresql_schema_candidates(adapter_root, adapter) if adapter == 'postgresql'
  candidates
end

#collect_candidates(glob:, schema:, source:, origin:, priority:) ⇒ Array<Arfi::Commands::candidate>

Collect SQL file candidates matching a glob pattern, skipping underscore-prefixed files.

Parameters:

  • glob (Pathname) —

    Glob pattern to match SQL files

  • schema (String) —

    Schema name to assign to all matched files

  • source (String) —

    Source type ('generic' or adapter name)

  • origin (String) —

    Origin type ('legacy' for root level, 'explicit' for public/ subdirectory)

  • priority (Integer) —

    Numeric priority for override resolution (higher = preferred)

  • glob: (::Pathname)
  • schema: (String)
  • source: (String)
  • origin: (String)
  • priority: (Integer)

Returns:

  • (Array<Arfi::Commands::candidate>)


118
119
120
121
122
123
124
125
126
127
128
129
130
# File 'lib/arfi/commands/functions_candidates.rb', line 118

def collect_candidates(glob:, schema:, source:, origin:, priority:)
  Dir.glob(glob.to_s).filter_map do |path|
    base = File.basename(path)
    next if base.start_with?('_')

    key = "#{schema}/#{base}"
    function_name = File.basename(path, '.sql')
    {
      key: key, schema: schema, function: function_name,
      source: source, origin: origin, priority: priority, path: path
    }
  end
end

#collect_postgresql_schema_candidates(adapter_root, adapter) ⇒ Array<Arfi::Commands::candidate>

Collect function candidates from PostgreSQL-specific schema subdirectories (except public).

Parameters:

  • adapter_root (Pathname) —

    PostgreSQL adapter root directory

  • adapter (String) —

    Database adapter name

Returns:

  • (Array<Arfi::Commands::candidate>)


96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/arfi/commands/functions_candidates.rb', line 96

def collect_postgresql_schema_candidates(adapter_root, adapter)
  Dir.children(adapter_root).sort.each_with_object([]) do |child, acc|
    next if child.start_with?('_')
    next if child == DEFAULT_SCHEMA

    dir = adapter_root.join(child)
    next unless dir.directory?

    acc.concat collect_candidates(glob: dir.join('*.sql'), schema: child, source: adapter,
                                  origin: 'explicit', priority: 10)
  end
end

#generic_candidates(root) ⇒ Array<Arfi::Commands::candidate>

Collect generic function candidates from legacy root and explicit public/ directory.

Parameters:

  • root (Pathname) —

    Project root directory (Rails.root/db/functions)

Returns:

  • (Array<Arfi::Commands::candidate>)


66
67
68
69
70
71
72
73
# File 'lib/arfi/commands/functions_candidates.rb', line 66

def generic_candidates(root)
  candidates = [] # steep:ignore
  candidates.concat collect_candidates(glob: root.join('*.sql'), schema: DEFAULT_SCHEMA, source: 'generic',
                                       origin: 'legacy', priority: 1)
  candidates.concat collect_candidates(glob: root.join(DEFAULT_SCHEMA, '*.sql'), schema: DEFAULT_SCHEMA,
                                       source: 'generic', origin: 'explicit', priority: 2)
  candidates
end

#group_candidates_by_key(candidates) ⇒ Hash<String, Array<Arfi::Commands::candidate>>

Group candidates by their schema/function key, sorted by priority within each group.

Parameters:

  • candidates (Array<Arfi::Commands::candidate>) —

    Flat list of candidates

Returns:

  • (Hash<String, Array<Arfi::Commands::candidate>>)


30
31
32
33
34
35
36
37
# File 'lib/arfi/commands/functions_candidates.rb', line 30

def group_candidates_by_key(candidates)
  by_key = Hash.new { |h, k| h[k] = [] } # steep:ignore
  candidates.each do |c|
    by_key[c[:key]] << c
  end
  by_key.each_value { |arr| arr.sort_by! { |c| c[:priority] } }
  by_key
end

#rel(path) ⇒ String

Convert an absolute filesystem path to a project-relative path.

Parameters:

  • path (Pathname, String) —

    Absolute filesystem path

Returns:

  • (String) —

    Relative path starting from Rails.root



55
56
57
58
59
# File 'lib/arfi/commands/functions_candidates.rb', line 55

def rel(path)
  root = Rails.root.to_s
  p = path.to_s
  p.start_with?(root) ? p.sub(root + File::SEPARATOR, '') : p
end