1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# Each card's place in a list (Contact#sort_key), so a group's first
# few members by that order are a query rather than the whole group
# built and sorted to take them from — `sync:*` holds every card, and
# a contact's tag for it names five
# (docs/plans/2026-10-22-perceived-speed.md). Index, like
# search_keys: filled through the app's own Contact#sort_key, since
# what it must agree with is the order a list sorts in. A group lends
# no name, so the stored card alone decides it.
require "pro_tacts/contact"
require "pro_tacts/vcard"

Sequel.migration do
  up do
    create_table(:sort_keys, strict: true) do
      foreign_key :card_id, :cards, type: String, text: true, primary_key: true, null: false, on_delete: :cascade
      String :sort_key, text: true, null: false

      index [:sort_key, :card_id]
    end

    self[:cards].order(:id).each do |row|
      id = row.fetch(:id)
      contact = ProTacts::Contact.new(id:, stored: ProTacts::VCard.new(row.fetch(:vcard)), birthday: nil, inherited: [])
      self[:sort_keys].insert(card_id: id, sort_key: contact.sort_key)
    end
  end

  down do
    drop_table(:sort_keys)
  end
end