Class: TocDoc::Availability::Collection

Inherits:
Object
  • Object
show all
Includes:
Enumerable
Defined in:
lib/toc_doc/models/availability/collection.rb

Overview

An Enumerable collection of TocDoc::Availability instances returned by where.

Examples:

Iterate over available slots

collection = TocDoc::Availability.where(visit_motive_ids: 123, agenda_ids: 456)
collection.each { |avail| puts avail.date }

Access metadata

collection.total      #=> 5
collection.next_slot  #=> "2026-02-28T10:00:00.000+01:00"

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(data, query: {}, path: '/availabilities.json', client: nil) ⇒ Collection

Returns a new instance of Collection.

Parameters:

  • data (Hash)

    parsed first-page response body

  • query (Hash) (defaults to: {})

    original query params (used to build next-page requests)

  • path (String) (defaults to: '/availabilities.json')

    API path for subsequent requests

  • client (TocDoc::Client, nil) (defaults to: nil)

    client used to fetch additional pages via #load_next!; +nil+ disables #load_next!



28
29
30
31
32
33
# File 'lib/toc_doc/models/availability/collection.rb', line 28

def initialize(data, query: {}, path: '/availabilities.json', client: nil)
  @data = data.dup
  @query = query
  @path = path
  @client = client
end

Instance Attribute Details

#pathObject (readonly)

Returns the value of attribute path.



21
22
23
# File 'lib/toc_doc/models/availability/collection.rb', line 21

def path
  @path
end

#queryObject (readonly)

Returns the value of attribute query.



21
22
23
# File 'lib/toc_doc/models/availability/collection.rb', line 21

def query
  @query
end

Instance Method Details

#availabilitiesArray<TocDoc::Availability> Also known as: all

All TocDoc::Availability instances that have at least one slot.

Results are memoized and invalidated by #merge_page!.

Returns:



40
41
42
43
44
# File 'lib/toc_doc/models/availability/collection.rb', line 40

def availabilities
  @availabilities ||= Array(@data['availabilities'])
                      .select { |entry| Array(entry['slots']).any? }
                      .map { |entry| TocDoc::Availability.new(entry) }
end

#booking_urlString?

Builds a Doctolib booking URL for the current query context.

Requires +booking_slug+ to have been passed as an option to TocDoc::Availability.where. Returns +nil+ when absent.

The URL targets the motive-selection step of the booking funnel, pre-filled with the first practice ID and the visit motive IDs from the original query.

Examples:

collection = TocDoc::Availability.where(
  visit_motive_ids: 1830057,
  agenda_ids: 2359638,
  booking_slug: 'dentiste/bordeaux/jane-doe'
)
collection.booking_url
#=> "https://www.doctolib.fr/dentiste/bordeaux/jane-doe/booking/motives?pid=practice-125055&vmids[]=1830057"

Returns:

  • (String, nil)

    fully-qualified booking URL, or +nil+ if +booking_slug+ was not provided



168
169
170
171
172
173
174
175
# File 'lib/toc_doc/models/availability/collection.rb', line 168

def booking_url
  return unless @query[:booking_slug]

  practice_id = [@query[:practice_ids]].flatten.first
  "#{TocDoc.api_endpoint}/#{@query[:booking_slug]}/booking/motives" \
    "?pid=practice-#{practice_id}" \
    "&vmids[]=#{@query[:visit_motive_ids]}"
end

#each {|availability| ... } ⇒ Enumerator

Iterates over TocDoc::Availability instances that have at least one slot.

Yield Parameters:

Returns:

  • (Enumerator)

    if no block given



59
60
61
# File 'lib/toc_doc/models/availability/collection.rb', line 59

def each(&)
  availabilities.each(&)
end

#load_next!self

Fetches the next window of availabilities and merges it into this collection.

Uses the +next_slot+ date from the API response as the +start_date+ for the follow-up request.

Examples:

collection.load_next! if collection.more?

Returns:

  • (self)

Raises:

  • (TocDoc::Error)

    if no client was provided at construction time

  • (StopIteration)

    if #more? is +false+



107
108
109
110
111
112
113
114
115
116
# File 'lib/toc_doc/models/availability/collection.rb', line 107

def load_next!
  raise TocDoc::Error, 'No client available for pagination' unless @client
  raise StopIteration, 'No more pages available' unless more?

  next_date = Date.parse(@data['next_slot']).to_s
  next_page = @client.get(@path, query: @query.merge(start_date: next_date))
  @data.delete('next_slot')
  @data['next_slot'] = next_page['next_slot'] if next_page.key?('next_slot')
  merge_page!(next_page)
end

#merge_page!(page_data) ⇒ self

Fetches the next window of availabilities (starting the day after the last date in the current collection) and merges them in.

Parameters:

  • page_data (Hash)

    parsed response body to merge into this collection

Returns:

  • (self)


141
142
143
144
145
146
# File 'lib/toc_doc/models/availability/collection.rb', line 141

def merge_page!(page_data)
  @data['availabilities'] = @data.fetch('availabilities', []) + page_data.fetch('availabilities', [])
  @data['total']          = @data.fetch('total', 0) + page_data.fetch('total', 0)
  @availabilities = nil
  self
end

#more?Boolean

Returns +true+ when the API has indicated that more results exist beyond the currently loaded pages.

Returns:

  • (Boolean)


92
93
94
# File 'lib/toc_doc/models/availability/collection.rb', line 92

def more?
  !!@data['next_slot']
end

#next_slotString?

The nearest available appointment slot.

Returns the +next_slot+ value from the API when present (which only occurs when none of the loaded dates have any slots). Otherwise returns the first slot of the first date that has one.

Returns:

  • (String, nil)

    ISO 8601 datetime string, or +nil+ when unavailable



77
78
79
80
81
82
83
84
85
86
# File 'lib/toc_doc/models/availability/collection.rb', line 77

def next_slot
  return @data['next_slot'] if @data.key?('next_slot')

  Array(@data['availabilities']).each do |entry|
    slots = Array(entry['slots'])
    return slots.first unless slots.empty?
  end

  nil
end

#raw_availabilitiesArray<TocDoc::Availability>

All date entries — including those with no slots — as TocDoc::Availability objects.

Returns:



122
123
124
# File 'lib/toc_doc/models/availability/collection.rb', line 122

def raw_availabilities
  Array(@data['availabilities']).map { |entry| TocDoc::Availability.new(entry) }
end

#slotsArray<DateTime>

All individual slots across every availability in the collection.

Returns:

  • (Array<DateTime>)


51
52
53
# File 'lib/toc_doc/models/availability/collection.rb', line 51

def slots
  availabilities.flat_map(&:slots)
end

#to_hHash{String => Object}

Returns a plain Hash representation of the collection.

The +availabilities+ key contains only dates with slots (filtered), serialised back to plain Hashes.

Returns:

  • (Hash{String => Object})


132
133
134
# File 'lib/toc_doc/models/availability/collection.rb', line 132

def to_h
  @data.merge('availabilities' => availabilities.map(&:to_h))
end

#totalInteger

The total number of available slots in the collection.

Returns:

  • (Integer)


66
67
68
# File 'lib/toc_doc/models/availability/collection.rb', line 66

def total
  @data['total']
end