Skip to main content

Overview

The SeekersHandler protocol provides methods to fetch all seekers or specific seekers by identifier, with comprehensive support for pagination and filtering. The default implementation SalesforceSeekersHandler handles all seeker-related operations using the Salesforce API.

Protocol Definition

public protocol SeekersHandler: Sendable

Methods

Fetch All Seekers (Paginated)

Fetches all seekers with pagination and optional filters.
func fetchAll(
    pageNumber: Int?,
    pageSize: Int?,
    seekerId: String?,
    name: String?,
    campus: Campus?,
    leadStatus: LeadStatus?,
    email: String?,
    leadId: String?,
    contactNumber: String?
) async throws -> SeekerResponse
pageNumber
Int?
The page number to fetch (optional, default 1)
pageSize
Int?
The page size to fetch (optional, default 50)
seekerId
String?
Filter by seeker ID (optional)
name
String?
Filter by name (optional)
campus
Campus?
Filter by campus (optional, type-safe)Possible Values:
  • .eastCampus - “East Campus”
  • .westCampus - “West Campus”
  • .campusOne - “Campus One”
  • .campusTwo - “Campus Two”
  • .campusThree - “Campus Three”
  • .campusFour - “Campus Four”
  • .teenXYouth - “Teen X Youth”
  • .hiTechCity - “Hitech City”
leadStatus
LeadStatus?
Filter by lead status (optional, type-safe)Possible Values:
  • .attempted
  • .followUp
  • .secondFollowUp
  • .thirdFollowUp
  • .fourthFollowUp
  • .lost
  • .converted
  • .doNotContact
  • .unknown
email
String?
Filter by email (optional)
leadId
String?
Filter by lead ID (optional)
contactNumber
String?
Filter by contact number (optional)
returns
SeekerResponse
A SeekerResponse containing seekers and pagination info
throws
SeekerError
Throws SeekerError if operation fails

Fetch All Seekers (Cursor-based Pagination)

Fetches all seekers with cursor-based pagination support using nextPageToken.
func fetchAll(
    pageNumber: Int?,
    pageSize: Int?,
    nextPageToken: String?,
    seekerId: String?,
    name: String?,
    campus: Campus?,
    leadStatus: LeadStatus?,
    email: String?,
    leadId: String?,
    contactNumber: String?
) async throws -> SeekerResponse
nextPageToken
String?
The next page token for cursor-based pagination (optional)
All other parameters are the same as the paginated version above.

Fetch Seeker by Identifier

Fetches a specific seeker by identifier (leadId or phone, case-insensitive).
func fetch(identifier: String) async throws -> Seeker
identifier
String
required
The identifier to fetch (leadId or phone number)
returns
Seeker
The seeker if found
throws
SeekerError
Throws SeekerError.seekerNotFound if seeker not found, or SeekerError.invalidIdentifier if identifier is invalid

Fetch All Seekers (Non-paginated)

Fetches all seekers without pagination.
func fetchAll() async throws -> [Seeker]
returns
[Seeker]
Array of all seekers
throws
SeekerError
Throws SeekerError if operation fails

Implementation

SalesforceSeekersHandler

The default implementation of SeekersHandler for Salesforce.
public struct SalesforceSeekersHandler: SeekersHandler {
    public init(
        salesforceClient: SalesforceClient,
        accessToken: String,
        instanceUrl: String
    )
}
salesforceClient
SalesforceClient
required
The Salesforce client instance
accessToken
String
required
The OAuth access token for Salesforce API authentication
instanceUrl
String
required
The Salesforce instance URL

Usage Examples

Basic Fetch with Pagination

import CongregationKit

// Access the seekers handler through congregation
let response = try await congregation.seekers.fetchAll(
    pageNumber: 1,
    pageSize: 50,
    seekerId: nil,
    name: nil,
    campus: nil,
    leadStatus: nil,
    email: nil,
    leadId: nil,
    contactNumber: nil
)

print("Found \(response.seekers.count) seekers")
if let metadata = response.metadata {
    print("Page \(metadata.page ?? 0) of \(metadata.total ?? 0) total records")
}

Fetch with Filters

// Fetch seekers from East Campus with attempted status
let response = try await congregation.seekers.fetchAll(
    pageNumber: 1,
    pageSize: 20,
    seekerId: nil,
    name: nil,
    campus: .eastCampus,
    leadStatus: .attempted,
    email: nil,
    leadId: nil,
    contactNumber: nil
)

for seeker in response.seekers {
    print("Name: \(seeker.fullName ?? "Unknown")")
    print("Lead Status: \(seeker.lead?.status?.displayName ?? "Unknown")")
}

Search by Name and Email

// Search for seekers with specific criteria
let response = try await congregation.seekers.fetchAll(
    pageNumber: 1,
    pageSize: 10,
    seekerId: nil,
    name: "John",
    campus: nil,
    leadStatus: nil,
    email: "[email protected]",
    leadId: nil,
    contactNumber: nil
)

Fetch Specific Seeker

// Fetch by lead ID
let seeker = try await congregation.seekers.fetch(
    identifier: "LEAD12345"
)

print("Found: \(seeker.fullName ?? "Unknown")")
print("Email: \(seeker.email ?? "Not provided")")

// Fetch by phone number
let seekerByPhone = try await congregation.seekers.fetch(
    identifier: "+1234567890"
)

Cursor-based Pagination

// First page
var response = try await congregation.seekers.fetchAll(
    pageNumber: 1,
    pageSize: 50,
    nextPageToken: nil,
    seekerId: nil,
    name: nil,
    campus: .westCampus,
    leadStatus: .followUp,
    email: nil,
    leadId: nil,
    contactNumber: nil
)

// Process first page
for seeker in response.seekers {
    // Process seeker
}

// Fetch next page using token
if let nextToken = response.metadata?.nextPageToken {
    response = try await congregation.seekers.fetchAll(
        pageNumber: nil,
        pageSize: 50,
        nextPageToken: nextToken,
        seekerId: nil,
        name: nil,
        campus: .westCampus,
        leadStatus: .followUp,
        email: nil,
        leadId: nil,
        contactNumber: nil
    )
}

Fetch All Seekers (Non-paginated)

// Get all seekers at once
let allSeekers = try await congregation.seekers.fetchAll()

print("Total seekers: \(allSeekers.count)")

// Process all seekers
for seeker in allSeekers {
    if let entryType = seeker.typeOfEntry {
        switch entryType {
        case .salvation:
            print("Salvation: \(seeker.fullName ?? "Unknown")")
        case .newVisitor:
            print("New Visitor: \(seeker.fullName ?? "Unknown")")
        default:
            break
        }
    }
}

Response Types

SeekerResponse

public struct SeekerResponse: Codable, Sendable {
    public let seekers: [Seeker]
    public let metadata: Metadata?
    public let error: Bool?
    public let message: String?
    
    public struct Metadata: Codable, Sendable {
        public let per: Int?
        public let total: Int?
        public let page: Int?
        public let nextPageToken: String?
        public let previousPageToken: String?
    }
    
    // Helper properties
    public var isPaginated: Bool
    public var paginationInfo: (per: Int, total: Int, page: Int)?
}

Error Handling

SeekerError

public enum SeekerError: Error, LocalizedError, Sendable {
    case seekerNotFound
    case invalidSeekerData
    case fetchFailed(Error)
    case invalidIdentifier
}
Error Cases:
  • seekerNotFound - Seeker not found
  • invalidSeekerData - Invalid seeker data received
  • fetchFailed(Error) - Failed to fetch seeker data with underlying error
  • invalidIdentifier - Identifier must be a valid leadId or phone number

Example Error Handling

do {
    let seeker = try await congregation.seekers.fetch(
        identifier: "LEAD12345"
    )
    print("Found: \(seeker.fullName ?? "Unknown")")
} catch SeekerError.seekerNotFound {
    print("Seeker not found")
} catch SeekerError.invalidIdentifier {
    print("Invalid identifier provided")
} catch SeekerError.fetchFailed(let error) {
    print("Fetch failed: \(error.localizedDescription)")
} catch {
    print("Unexpected error: \(error)")
}

See Also

Build docs developers (and LLMs) love