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
The root member of the family tree (typically the oldest generation).
All nodes in the family tree.
All edges (relationships) in the family tree.
Computed Properties
Number of generations in the tree.
The minimum generation number.
The maximum generation number.
Total number of members in the tree.
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)")
Navigating Generations
// 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
The member represented by this node.
The generation level (0 = root, negative = ancestors, positive = descendants).
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
The source member’s ID (from).
The target member’s ID (to).
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