Skip to main content

Overview

The FamilyTree struct provides a graph-based view of family relationships, supporting tree visualization, relationship navigation, and genealogical analysis. It represents families as a hierarchical structure with nodes (members) and edges (relationships).

Type Definition

public struct FamilyTree: Codable, Sendable

Properties

rootMember
Member
required
The root member of the family tree (typically the oldest generation).
nodes
[FamilyTreeNode]
required
All nodes in the family tree.
edges
[FamilyTreeEdge]
required
All edges (relationships) in the family tree.

Computed Properties

generationCount
Int
Number of generations in the tree.
minGeneration
Int
The minimum generation number.
maxGeneration
Int
The maximum generation number.
memberCount
Int
Total number of members in the tree.
relationshipCount
Int
Total number of relationships in the tree.

Initializer

public init(
    rootMember: Member,
    nodes: [FamilyTreeNode],
    edges: [FamilyTreeEdge]
)

Parameters

  • rootMember: The root member of the tree
  • nodes: All tree nodes
  • edges: All tree edges

Methods

nodes(inGeneration:)

Gets all nodes in a specific generation.
public func nodes(inGeneration generation: Int) -> [FamilyTreeNode]

Parameters

  • generation: The generation number (0 = root generation)

Returns

Array of nodes in that generation.

Example

let tree = try await congregation.families.buildFamilyTree(
    startingFrom: memberId
)

// Get root generation (grandparents)
let generation0 = tree.nodes(inGeneration: 0)
print("Grandparents: \(generation0.count)")

// Get first descendant generation (parents)
let generation1 = tree.nodes(inGeneration: 1)
print("Parents: \(generation1.count)")

// Get second descendant generation (children)
let generation2 = tree.nodes(inGeneration: 2)
print("Children: \(generation2.count)")

edges(from:)

Gets all edges originating from a specific member.
public func edges(from memberId: MemberID) -> [FamilyTreeEdge]

Parameters

  • memberId: The source member’s ID

Returns

Array of edges from that member.

Example

let parentEdges = tree.edges(from: parentMemberId)
for edge in parentEdges {
    print("\(edge.relationshipType.displayName) to \(edge.to)")
}

edges(to:)

Gets all edges pointing to a specific member.
public func edges(to memberId: MemberID) -> [FamilyTreeEdge]

Parameters

  • memberId: The target member’s ID

Returns

Array of edges to that member.

Example

let childEdges = tree.edges(to: childMemberId)
for edge in childEdges {
    print("\(edge.relationshipType.displayName) from \(edge.from)")
}

node(for:)

Finds a node by member ID.
public func node(for memberId: MemberID) -> FamilyTreeNode?

Parameters

  • memberId: The member’s ID

Returns

The tree node if found.

Example

if let node = tree.node(for: memberId) {
    print("Generation: \(node.generation)")
    print("Position: \(node.position)")
    print("Name: \(node.member.memberName ?? "Unknown")")
}

Example Usage

Building a Family Tree

let congregation = CongregationKit(auth: auth)

// Build tree from a specific member
let tree = try await congregation.families.buildFamilyTree(
    startingFrom: MemberID(rawValue: "TKT1234")!
)

print("Family Tree Statistics:")
print("- Generations: \(tree.generationCount)")
print("- Total members: \(tree.memberCount)")
print("- Total relationships: \(tree.relationshipCount)")
print("- Generation range: \(tree.minGeneration)...\(tree.maxGeneration)")
// Iterate through all generations
for generation in tree.minGeneration...tree.maxGeneration {
    let members = tree.nodes(inGeneration: generation)
    print("Generation \(generation): \(members.count) members")
    
    for node in members {
        let name = node.member.memberName ?? "Unknown"
        print("  - \(name) (position: \(node.position))")
    }
}

Analyzing Relationships

// Find all parent-child relationships
let parentChildEdges = tree.edges.filter { 
    $0.relationshipType == .parent || $0.relationshipType == .child 
}

print("Parent-child relationships: \(parentChildEdges.count)")

// Find all spouse relationships
let spouseEdges = tree.edges.filter { 
    $0.relationshipType == .spouse 
}

print("Spouse relationships: \(spouseEdges.count)")

Tracing Lineage

// Find all descendants of a member
func findDescendants(of memberId: MemberID, in tree: FamilyTree) -> [Member] {
    var descendants: [Member] = []
    var toProcess = [memberId]
    
    while let currentId = toProcess.popLast() {
        let childEdges = tree.edges(from: currentId).filter { 
            $0.relationshipType == .parent 
        }
        
        for edge in childEdges {
            if let node = tree.node(for: edge.to) {
                descendants.append(node.member)
                toProcess.append(edge.to)
            }
        }
    }
    
    return descendants
}

let descendants = findDescendants(of: ancestorId, in: tree)
print("Found \(descendants.count) descendants")

Supporting Types

FamilyTreeNode

A node in the family tree representing a single member.
public struct FamilyTreeNode: Codable, Sendable
member
Member
required
The member represented by this node.
generation
Int
required
The generation level (0 = root, negative = ancestors, positive = descendants).
position
Int
required
Horizontal position within the generation (for layout purposes).

Initializer

public init(member: Member, generation: Int, position: Int)

Example

let node = FamilyTreeNode(
    member: member,
    generation: 0,
    position: 0
)

FamilyTreeEdge

An edge in the family tree representing a relationship.
public struct FamilyTreeEdge: Codable, Equatable, Sendable
from
MemberID
required
The source member’s ID (from).
to
MemberID
required
The target member’s ID (to).
relationshipType
RelationshipType
required
The type of relationship.

Initializer

public init(
    from: MemberID,
    to: MemberID,
    relationshipType: RelationshipType
)

Example

let edge = FamilyTreeEdge(
    from: MemberID(rawValue: "TKT1234")!,
    to: MemberID(rawValue: "TKT5678")!,
    relationshipType: .parent
)

Visualization Example

Simple Text-Based Tree

func printFamilyTree(_ tree: FamilyTree) {
    for generation in tree.minGeneration...tree.maxGeneration {
        let indent = String(repeating: "  ", count: generation - tree.minGeneration)
        let nodes = tree.nodes(inGeneration: generation)
        
        print("\nGeneration \(generation):")
        for node in nodes.sorted(by: { $0.position < $1.position }) {
            let name = node.member.memberName ?? "Unknown"
            let age = node.member.dateOfBirth?.age.map { "(\($0))" } ?? ""
            print("\(indent)- \(name) \(age)")
            
            // Show relationships
            let edges = tree.edges(from: node.member.memberId ?? MemberID(rawValue: "UNKNOWN")!)
            for edge in edges {
                if let targetNode = tree.node(for: edge.to) {
                    let targetName = targetNode.member.memberName ?? "Unknown"
                    let relType = edge.relationshipType.displayName
                    print("\(indent)\(relType): \(targetName)")
                }
            }
        }
    }
}

printFamilyTree(tree)

See Also

Build docs developers (and LLMs) love