Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,49 @@ collection.data.each do |member|
end
```

### Search Members

Search for members within a program. Returns a bounded result set (max 10 results) with a `more_results` flag indicating if additional matches exist.

Valid parameter combinations:
- `born_on` + `employee_id`
- `born_on` + `first_name` + `last_name`
- `born_on` + `first_name` + `last_name` + `employee_id`
- `born_on` + `first_name_prefix` + `last_name_prefix`
- `born_on` + `first_name_prefix` + `last_name_prefix` + `employee_id`

```ruby
# Search by employee ID and DOB
result = client.programs('program-id').search_members(
born_on: '1980-01-15',
employee_id: 'EMP123'
)

result[:data].each do |member|
puts "#{member[:first_name]} #{member[:last_name]}"
end

puts "More results available" if result[:more_results]

# Search by name and DOB
result = client.programs('program-id').search_members(
born_on: '1980-01-15',
first_name: 'George',
last_name: 'Washington'
)

# Search by name prefix and DOB
result = client.programs('program-id').search_members(
born_on: '1980-01-15',
first_name_prefix: 'G',
last_name_prefix: 'Was'
)
```

Note: Unlike `list`, `search_members` does not support pagination. It returns up to 10 results with a `more_results` boolean. An `ArgumentError` will be raised if an invalid parameter combination is provided.

Note: Depending on your API key, `search_members` may be the only method you have access to. Contact your DataNexus representative for more information about your API key's permissions.

### Pagination

```ruby
Expand Down
76 changes: 76 additions & 0 deletions lib/data_nexus/resources/programs.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,18 @@ module Resources
# client.programs("program-uuid").members("member-id").consents.create(...)
# client.programs("program-uuid").members("member-id").enrollments.create(...)
#
# @example Search for members
# client.programs("program-uuid").search_members(born_on: "1976-07-04", employee_id: "ABC123")
#
class Programs
VALID_SEARCH_COMBINATIONS = [
%i[born_on first_name last_name employee_id],
%i[born_on first_name last_name],
%i[born_on first_name_prefix last_name_prefix employee_id],
%i[born_on first_name_prefix last_name_prefix],
%i[born_on employee_id]
].freeze

# @return [Connection] The HTTP connection
attr_reader :connection

Expand Down Expand Up @@ -65,6 +76,71 @@ def members(member_id = nil)
ProgramMembers.new(connection, program_id)
end
end

# Search for members within this program
#
# Returns a bounded result set (max 10 results). Use `more_results` to
# determine if additional matches exist beyond what was returned.
#
# Valid parameter combinations:
# - born_on, first_name, last_name, employee_id
# - born_on, first_name, last_name
# - born_on, first_name_prefix, last_name_prefix, employee_id
# - born_on, first_name_prefix, last_name_prefix
# - born_on, employee_id
#
# @param born_on [String] Date of birth (YYYY-MM-DD) - required for all searches
# @param first_name [String, nil] Exact first name match
# @param first_name_prefix [String, nil] First name prefix (min 1 char)
# @param last_name [String, nil] Exact last name match
# @param last_name_prefix [String, nil] Last name prefix (min 3 chars)
# @param employee_id [String, nil] Employee ID
#
# @return [Hash] Response with :data (Array) and :more_results (Boolean)
#
# @raise [ArgumentError] If params don't match a valid search combination
#
# @example Search by name and DOB
# client.programs("uuid").search_members(
# born_on: "1976-07-04",
# first_name: "george",
# last_name: "washington"
# )
#
# @example Search by prefix and DOB
# client.programs("uuid").search_members(
# born_on: "1976-07-04",
# first_name_prefix: "g",
# last_name_prefix: "was"
# )
#
# @example Search by employee ID and DOB
# client.programs("uuid").search_members(
# born_on: "1976-07-04",
# employee_id: "ABC1234"
# )
def search_members(**params)
validate_search_params!(params)

connection.post("/api/programs/#{program_id}/members/search", params)
end

private

def validate_search_params!(params)
provided_keys = params.keys.sort

return if VALID_SEARCH_COMBINATIONS.any? { |combo| combo.sort == provided_keys }

raise ArgumentError, invalid_search_params_message(provided_keys)
end

def invalid_search_params_message(provided_keys)
valid_combos = VALID_SEARCH_COMBINATIONS.map { |c| c.join(', ') }.join("\n - ")

"Invalid search parameter combination: #{provided_keys.join(', ')}. " \
"Valid combinations are:\n - #{valid_combos}"
end
end
end
end
53 changes: 53 additions & 0 deletions spec/cassettes/program_members/search_employee_id.yml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

45 changes: 45 additions & 0 deletions spec/cassettes/program_members/search_name.yml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

45 changes: 45 additions & 0 deletions spec/cassettes/program_members/search_prefix.yml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

64 changes: 64 additions & 0 deletions spec/integration/program_members_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -75,4 +75,68 @@
expect(household).to be_an(Array)
end
end

describe 'searching members' do
it 'returns members matching employee_id and DOB', vcr: { cassette_name: 'program_members/search_employee_id' } do
result = client.programs(program_id).search_members(
born_on: test_born_on,
employee_id: test_employee_id
)

expect(result).to be_a(Hash)
expect(result[:data]).to be_an(Array)
expect(result).to have_key(:more_results)
end

it 'returns members matching name and DOB', vcr: { cassette_name: 'program_members/search_name' } do
result = client.programs(program_id).search_members(
born_on: test_born_on,
first_name: 'Betty Jo',
last_name: 'Brown'
)

expect(result).to be_a(Hash)
expect(result[:data]).to be_an(Array)
expect(result).to have_key(:more_results)
end

it 'returns members matching name prefix and DOB', vcr: { cassette_name: 'program_members/search_prefix' } do
result = client.programs(program_id).search_members(
born_on: test_born_on,
first_name_prefix: 'Bet',
last_name_prefix: 'Bro'
)

expect(result).to be_a(Hash)
expect(result[:data]).to be_an(Array)
expect(result).to have_key(:more_results)
end

it 'raises ArgumentError for invalid parameter combinations' do
expect do
client.programs(program_id).search_members(
born_on: test_born_on,
first_name: 'George'
)
end.to raise_error(ArgumentError, /Invalid search parameter combination/)
end

it 'raises ArgumentError when mixing prefix and exact name params' do
expect do
client.programs(program_id).search_members(
born_on: test_born_on,
first_name: 'George',
last_name_prefix: 'Was'
)
end.to raise_error(ArgumentError, /Invalid search parameter combination/)
end

it 'raises ArgumentError when born_on is missing' do
expect do
client.programs(program_id).search_members(
employee_id: test_employee_id
)
end.to raise_error(ArgumentError, /Invalid search parameter combination/)
end
end
end
3 changes: 2 additions & 1 deletion spec/support/vcr.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
# Match requests on method and path only (ignore query params for flexibility)
config.default_cassette_options = {
record: :once,
match_requests_on: %i[method path]
match_requests_on: %i[method path],
allow_playback_repeats: true
}
end