@elaraai/e3-ui 1.0.97 → 1.0.98

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (304) hide show
  1. package/dist/src/allocation/index.d.ts +258 -7
  2. package/dist/src/allocation/index.d.ts.map +1 -1
  3. package/dist/src/allocation/index.js +30 -1
  4. package/dist/src/allocation/index.js.map +1 -1
  5. package/dist/src/allocation/types.d.ts +41 -0
  6. package/dist/src/allocation/types.d.ts.map +1 -1
  7. package/dist/src/allocation/types.js +35 -0
  8. package/dist/src/allocation/types.js.map +1 -1
  9. package/dist/src/bind/data-indexed.d.ts +31 -4
  10. package/dist/src/bind/data-indexed.d.ts.map +1 -1
  11. package/dist/src/bind/data-indexed.js +54 -10
  12. package/dist/src/bind/data-indexed.js.map +1 -1
  13. package/dist/src/calendar/index.d.ts +540 -14
  14. package/dist/src/calendar/index.d.ts.map +1 -1
  15. package/dist/src/calendar/index.js +43 -7
  16. package/dist/src/calendar/index.js.map +1 -1
  17. package/dist/src/calendar/paged.d.ts +89 -0
  18. package/dist/src/calendar/paged.d.ts.map +1 -0
  19. package/dist/src/calendar/paged.js +148 -0
  20. package/dist/src/calendar/paged.js.map +1 -0
  21. package/dist/src/flowchart/payload.d.ts +156 -0
  22. package/dist/src/flowchart/payload.d.ts.map +1 -1
  23. package/dist/src/flowchart/window.d.ts +12 -0
  24. package/dist/src/flowchart/window.d.ts.map +1 -1
  25. package/dist/src/index.d.ts +11 -2
  26. package/dist/src/index.d.ts.map +1 -1
  27. package/dist/src/index.js +19 -0
  28. package/dist/src/index.js.map +1 -1
  29. package/dist/src/internal.d.ts +11 -5
  30. package/dist/src/internal.d.ts.map +1 -1
  31. package/dist/src/internal.js +28 -7
  32. package/dist/src/internal.js.map +1 -1
  33. package/dist/src/plan/builders.d.ts +12 -8
  34. package/dist/src/plan/builders.d.ts.map +1 -1
  35. package/dist/src/plan/builders.js +12 -8
  36. package/dist/src/plan/builders.js.map +1 -1
  37. package/dist/src/plan/event-rows.d.ts +228 -156
  38. package/dist/src/plan/event-rows.d.ts.map +1 -1
  39. package/dist/src/plan/event-rows.js +239 -54
  40. package/dist/src/plan/event-rows.js.map +1 -1
  41. package/dist/src/plan/index.d.ts +5 -0
  42. package/dist/src/plan/index.d.ts.map +1 -1
  43. package/dist/src/plan/index.js +3 -0
  44. package/dist/src/plan/index.js.map +1 -1
  45. package/dist/src/plan/ir.d.ts +70 -0
  46. package/dist/src/plan/ir.d.ts.map +1 -1
  47. package/dist/src/plan/ordered-source.d.ts +2038 -1
  48. package/dist/src/plan/ordered-source.d.ts.map +1 -1
  49. package/dist/src/plan/ordered-source.js +19 -11
  50. package/dist/src/plan/ordered-source.js.map +1 -1
  51. package/dist/src/plan/plan.d.ts +513 -32
  52. package/dist/src/plan/plan.d.ts.map +1 -1
  53. package/dist/src/plan/plan.js +119 -32
  54. package/dist/src/plan/plan.js.map +1 -1
  55. package/dist/src/plan/root.d.ts +4 -2
  56. package/dist/src/plan/root.d.ts.map +1 -1
  57. package/dist/src/plan/root.js +6 -4
  58. package/dist/src/plan/root.js.map +1 -1
  59. package/dist/src/plan/series.d.ts +13 -0
  60. package/dist/src/plan/series.d.ts.map +1 -1
  61. package/dist/src/plan/series.js +61 -7
  62. package/dist/src/plan/series.js.map +1 -1
  63. package/dist/src/plan/types.d.ts +14 -0
  64. package/dist/src/plan/types.d.ts.map +1 -1
  65. package/dist/src/plan/types.js +8 -0
  66. package/dist/src/plan/types.js.map +1 -1
  67. package/dist/src/roster/index.d.ts +608 -20
  68. package/dist/src/roster/index.d.ts.map +1 -1
  69. package/dist/src/roster/index.js +103 -29
  70. package/dist/src/roster/index.js.map +1 -1
  71. package/dist/src/roster/library.d.ts +12 -2
  72. package/dist/src/roster/library.d.ts.map +1 -1
  73. package/dist/src/roster/library.js +8 -0
  74. package/dist/src/roster/library.js.map +1 -1
  75. package/dist/src/roster/lists.d.ts +59 -12
  76. package/dist/src/roster/lists.d.ts.map +1 -1
  77. package/dist/src/roster/lists.js +51 -58
  78. package/dist/src/roster/lists.js.map +1 -1
  79. package/dist/src/roster/times.d.ts +402 -0
  80. package/dist/src/roster/times.d.ts.map +1 -1
  81. package/dist/src/roster/types.d.ts +913 -1
  82. package/dist/src/roster/types.d.ts.map +1 -1
  83. package/dist/src/roster/types.js +43 -3
  84. package/dist/src/roster/types.js.map +1 -1
  85. package/dist/src/schedule/cell-checks.d.ts +85 -0
  86. package/dist/src/schedule/cell-checks.d.ts.map +1 -0
  87. package/dist/src/schedule/cell-checks.js +211 -0
  88. package/dist/src/schedule/cell-checks.js.map +1 -0
  89. package/dist/src/schedule/events.d.ts +42 -10
  90. package/dist/src/schedule/events.d.ts.map +1 -1
  91. package/dist/src/schedule/events.js +349 -155
  92. package/dist/src/schedule/events.js.map +1 -1
  93. package/dist/src/schedule/fields.d.ts +134 -0
  94. package/dist/src/schedule/fields.d.ts.map +1 -0
  95. package/dist/src/schedule/fields.js +207 -0
  96. package/dist/src/schedule/fields.js.map +1 -0
  97. package/dist/src/schedule/library.d.ts +11 -3
  98. package/dist/src/schedule/library.d.ts.map +1 -1
  99. package/dist/src/schedule/library.js +9 -6
  100. package/dist/src/schedule/library.js.map +1 -1
  101. package/dist/src/schedule/optimise.d.ts +124 -0
  102. package/dist/src/schedule/optimise.d.ts.map +1 -0
  103. package/dist/src/schedule/optimise.js +140 -0
  104. package/dist/src/schedule/optimise.js.map +1 -0
  105. package/dist/src/schedule/pages.d.ts +76 -0
  106. package/dist/src/schedule/pages.d.ts.map +1 -0
  107. package/dist/src/schedule/pages.js +86 -0
  108. package/dist/src/schedule/pages.js.map +1 -0
  109. package/dist/src/schedule/record-window.d.ts +119 -6
  110. package/dist/src/schedule/record-window.d.ts.map +1 -1
  111. package/dist/src/schedule/record-window.js +139 -60
  112. package/dist/src/schedule/record-window.js.map +1 -1
  113. package/dist/src/schedule/resources.d.ts +8 -4
  114. package/dist/src/schedule/resources.d.ts.map +1 -1
  115. package/dist/src/schedule/resources.js +35 -15
  116. package/dist/src/schedule/resources.js.map +1 -1
  117. package/dist/src/schedule/session.d.ts +14 -0
  118. package/dist/src/schedule/session.d.ts.map +1 -1
  119. package/dist/src/schedule/session.js +29 -17
  120. package/dist/src/schedule/session.js.map +1 -1
  121. package/dist/src/schedule/types.d.ts +426 -36
  122. package/dist/src/schedule/types.d.ts.map +1 -1
  123. package/dist/src/schedule/types.js +63 -17
  124. package/dist/src/schedule/types.js.map +1 -1
  125. package/dist/src/schedule/window.d.ts +30 -9
  126. package/dist/src/schedule/window.d.ts.map +1 -1
  127. package/dist/src/schedule/window.js +101 -49
  128. package/dist/src/schedule/window.js.map +1 -1
  129. package/dist/src/schematic/index.d.ts +277 -0
  130. package/dist/src/schematic/index.d.ts.map +1 -0
  131. package/dist/src/schematic/index.js +206 -0
  132. package/dist/src/schematic/index.js.map +1 -0
  133. package/dist/src/schematic/kinds.d.ts +501 -0
  134. package/dist/src/schematic/kinds.d.ts.map +1 -0
  135. package/dist/src/schematic/kinds.js +1027 -0
  136. package/dist/src/schematic/kinds.js.map +1 -0
  137. package/dist/src/schematic/layers.d.ts +74 -0
  138. package/dist/src/schematic/layers.d.ts.map +1 -0
  139. package/dist/src/schematic/layers.js +99 -0
  140. package/dist/src/schematic/layers.js.map +1 -0
  141. package/dist/src/schematic/library.d.ts +202 -0
  142. package/dist/src/schematic/library.d.ts.map +1 -0
  143. package/dist/src/schematic/library.js +244 -0
  144. package/dist/src/schematic/library.js.map +1 -0
  145. package/dist/src/schematic/payload.d.ts +8360 -0
  146. package/dist/src/schematic/payload.d.ts.map +1 -0
  147. package/dist/src/schematic/payload.js +446 -0
  148. package/dist/src/schematic/payload.js.map +1 -0
  149. package/dist/src/schematic/schematic.d.ts +27 -0
  150. package/dist/src/schematic/schematic.d.ts.map +1 -0
  151. package/dist/src/schematic/schematic.js +17 -0
  152. package/dist/src/schematic/schematic.js.map +1 -0
  153. package/dist/src/schematic/shapes.d.ts +150 -0
  154. package/dist/src/schematic/shapes.d.ts.map +1 -0
  155. package/dist/src/schematic/shapes.js +171 -0
  156. package/dist/src/schematic/shapes.js.map +1 -0
  157. package/dist/src/schematic/templates.d.ts +96 -0
  158. package/dist/src/schematic/templates.d.ts.map +1 -0
  159. package/dist/src/schematic/templates.js +91 -0
  160. package/dist/src/schematic/templates.js.map +1 -0
  161. package/dist/src/schematic/types.d.ts +5766 -0
  162. package/dist/src/schematic/types.d.ts.map +1 -0
  163. package/dist/src/schematic/types.js +688 -0
  164. package/dist/src/schematic/types.js.map +1 -0
  165. package/dist/src/schematic/window.d.ts +212 -0
  166. package/dist/src/schematic/window.d.ts.map +1 -0
  167. package/dist/src/schematic/window.js +337 -0
  168. package/dist/src/schematic/window.js.map +1 -0
  169. package/dist/src/sheet/editing-bridge.d.ts +4 -2
  170. package/dist/src/sheet/editing-bridge.d.ts.map +1 -1
  171. package/dist/src/sheet/editing-bridge.js +8 -2
  172. package/dist/src/sheet/editing-bridge.js.map +1 -1
  173. package/dist/src/sheet/editing-types.d.ts +9 -5
  174. package/dist/src/sheet/editing-types.d.ts.map +1 -1
  175. package/dist/src/sheet/editing-types.js +9 -5
  176. package/dist/src/sheet/editing-types.js.map +1 -1
  177. package/dist/src/sheet/index.d.ts +18 -8
  178. package/dist/src/sheet/index.d.ts.map +1 -1
  179. package/dist/src/sheet/index.js +15 -7
  180. package/dist/src/sheet/index.js.map +1 -1
  181. package/dist/src/sheet/optimise.d.ts +69 -0
  182. package/dist/src/sheet/optimise.d.ts.map +1 -0
  183. package/dist/src/sheet/optimise.js +81 -0
  184. package/dist/src/sheet/optimise.js.map +1 -0
  185. package/dist/src/sheet/registers.d.ts +5 -5
  186. package/dist/src/sheet/registers.js +5 -5
  187. package/dist/src/sheet/root.d.ts +2 -0
  188. package/dist/src/sheet/root.d.ts.map +1 -1
  189. package/dist/src/sheet/root.js +2 -2
  190. package/dist/src/sheet/root.js.map +1 -1
  191. package/dist/src/sheet/sheet.d.ts +753 -573
  192. package/dist/src/sheet/sheet.d.ts.map +1 -1
  193. package/dist/src/sheet/sheet.js +45 -13
  194. package/dist/src/sheet/sheet.js.map +1 -1
  195. package/dist/src/sheet/types.d.ts +92 -12
  196. package/dist/src/sheet/types.d.ts.map +1 -1
  197. package/dist/src/sheet/types.js +4 -8
  198. package/dist/src/sheet/types.js.map +1 -1
  199. package/dist/src/utils/keyed-rows.d.ts +41 -0
  200. package/dist/src/utils/keyed-rows.d.ts.map +1 -0
  201. package/dist/src/utils/keyed-rows.js +64 -0
  202. package/dist/src/utils/keyed-rows.js.map +1 -0
  203. package/dist/src/utils/optimise.d.ts +79 -0
  204. package/dist/src/utils/optimise.d.ts.map +1 -0
  205. package/dist/src/utils/optimise.js +46 -0
  206. package/dist/src/utils/optimise.js.map +1 -0
  207. package/dist/test/allocation/allocation.examples.d.ts +6 -18
  208. package/dist/test/allocation/allocation.examples.d.ts.map +1 -1
  209. package/dist/test/allocation/allocation.examples.js +3 -3
  210. package/dist/test/allocation/allocation.examples.js.map +1 -1
  211. package/dist/test/allocation/optimise.examples.d.ts +109 -0
  212. package/dist/test/allocation/optimise.examples.d.ts.map +1 -0
  213. package/dist/test/allocation/optimise.examples.js +223 -0
  214. package/dist/test/allocation/optimise.examples.js.map +1 -0
  215. package/dist/test/bind/data/data.examples.d.ts +540 -36
  216. package/dist/test/bind/data/data.examples.d.ts.map +1 -1
  217. package/dist/test/bind/data/data.examples.js +66 -2
  218. package/dist/test/bind/data/data.examples.js.map +1 -1
  219. package/dist/test/bind/record/record.examples.d.ts +1 -3
  220. package/dist/test/bind/record/record.examples.d.ts.map +1 -1
  221. package/dist/test/calendar/calendar-records.examples.d.ts.map +1 -1
  222. package/dist/test/calendar/calendar-records.examples.js +3 -3
  223. package/dist/test/calendar/calendar-records.examples.js.map +1 -1
  224. package/dist/test/calendar/calendar-windows.examples.d.ts +9 -0
  225. package/dist/test/calendar/calendar-windows.examples.d.ts.map +1 -0
  226. package/dist/test/calendar/calendar-windows.examples.js +111 -0
  227. package/dist/test/calendar/calendar-windows.examples.js.map +1 -0
  228. package/dist/test/calendar/calendar.examples.d.ts +7 -21
  229. package/dist/test/calendar/calendar.examples.d.ts.map +1 -1
  230. package/dist/test/calendar/calendar.examples.js +7 -7
  231. package/dist/test/calendar/calendar.examples.js.map +1 -1
  232. package/dist/test/calendar/optimise.examples.d.ts +132 -0
  233. package/dist/test/calendar/optimise.examples.d.ts.map +1 -0
  234. package/dist/test/calendar/optimise.examples.js +75 -0
  235. package/dist/test/calendar/optimise.examples.js.map +1 -0
  236. package/dist/test/examples-package.d.ts +46 -10
  237. package/dist/test/examples-package.d.ts.map +1 -1
  238. package/dist/test/examples-package.js +142 -32
  239. package/dist/test/examples-package.js.map +1 -1
  240. package/dist/test/flowchart/flowchart.examples.d.ts +10 -30
  241. package/dist/test/flowchart/flowchart.examples.d.ts.map +1 -1
  242. package/dist/test/plan/optimise.examples.d.ts +207 -0
  243. package/dist/test/plan/optimise.examples.d.ts.map +1 -0
  244. package/dist/test/plan/optimise.examples.js +98 -0
  245. package/dist/test/plan/optimise.examples.js.map +1 -0
  246. package/dist/test/plan/plan-events.examples.d.ts +8 -24
  247. package/dist/test/plan/plan-events.examples.d.ts.map +1 -1
  248. package/dist/test/plan/plan-events.examples.js +3 -3
  249. package/dist/test/plan/plan-events.examples.js.map +1 -1
  250. package/dist/test/plan/plan-records.examples.d.ts +200 -19
  251. package/dist/test/plan/plan-records.examples.d.ts.map +1 -1
  252. package/dist/test/plan/plan-records.examples.js +125 -28
  253. package/dist/test/plan/plan-records.examples.js.map +1 -1
  254. package/dist/test/plan/plan-windows.examples.d.ts +853 -36
  255. package/dist/test/plan/plan-windows.examples.d.ts.map +1 -1
  256. package/dist/test/plan/plan-windows.examples.js +166 -29
  257. package/dist/test/plan/plan-windows.examples.js.map +1 -1
  258. package/dist/test/plan/plan.examples.d.ts +7 -21
  259. package/dist/test/plan/plan.examples.d.ts.map +1 -1
  260. package/dist/test/plan/plan.examples.js +11 -9
  261. package/dist/test/plan/plan.examples.js.map +1 -1
  262. package/dist/test/roster/domain.examples.d.ts +804 -0
  263. package/dist/test/roster/domain.examples.d.ts.map +1 -1
  264. package/dist/test/roster/domain.examples.js +3 -3
  265. package/dist/test/roster/domain.examples.js.map +1 -1
  266. package/dist/test/roster/optimise.examples.d.ts +485 -0
  267. package/dist/test/roster/optimise.examples.d.ts.map +1 -0
  268. package/dist/test/roster/optimise.examples.js +155 -0
  269. package/dist/test/roster/optimise.examples.js.map +1 -0
  270. package/dist/test/roster/roster-records.examples.d.ts +6 -18
  271. package/dist/test/roster/roster-records.examples.d.ts.map +1 -1
  272. package/dist/test/roster/roster-records.examples.js +1 -1
  273. package/dist/test/roster/roster-records.examples.js.map +1 -1
  274. package/dist/test/roster/roster.examples.d.ts +3391 -21
  275. package/dist/test/roster/roster.examples.d.ts.map +1 -1
  276. package/dist/test/roster/roster.examples.js +54 -7
  277. package/dist/test/roster/roster.examples.js.map +1 -1
  278. package/dist/test/roster/warehouse.d.ts +150 -7
  279. package/dist/test/roster/warehouse.d.ts.map +1 -1
  280. package/dist/test/roster/warehouse.js +36 -11
  281. package/dist/test/roster/warehouse.js.map +1 -1
  282. package/dist/test/schedule/schedule.examples.d.ts +1 -3
  283. package/dist/test/schedule/schedule.examples.d.ts.map +1 -1
  284. package/dist/test/schematic/schematic-records.examples.d.ts +444 -0
  285. package/dist/test/schematic/schematic-records.examples.d.ts.map +1 -0
  286. package/dist/test/schematic/schematic-records.examples.js +205 -0
  287. package/dist/test/schematic/schematic-records.examples.js.map +1 -0
  288. package/dist/test/schematic/schematic.examples.d.ts +2289 -0
  289. package/dist/test/schematic/schematic.examples.d.ts.map +1 -0
  290. package/dist/test/schematic/schematic.examples.js +453 -0
  291. package/dist/test/schematic/schematic.examples.js.map +1 -0
  292. package/dist/test/sheet/optimise.examples.d.ts +177 -0
  293. package/dist/test/sheet/optimise.examples.d.ts.map +1 -0
  294. package/dist/test/sheet/optimise.examples.js +75 -0
  295. package/dist/test/sheet/optimise.examples.js.map +1 -0
  296. package/dist/test/sheet/sheet-records.examples.d.ts +95 -204
  297. package/dist/test/sheet/sheet-records.examples.d.ts.map +1 -1
  298. package/dist/test/sheet/sheet-records.examples.js +42 -17
  299. package/dist/test/sheet/sheet-records.examples.js.map +1 -1
  300. package/dist/test/sheet/sheet.examples.d.ts +17 -33
  301. package/dist/test/sheet/sheet.examples.d.ts.map +1 -1
  302. package/dist/test/sheet/sheet.examples.js +18 -15
  303. package/dist/test/sheet/sheet.examples.js.map +1 -1
  304. package/package.json +11 -11
@@ -43,10 +43,22 @@
43
43
  * part)`, and the kind reads overlap queries through its declared interval
44
44
  * indexes (the source's `range` naming the start field). It shares the
45
45
  * toolbar's filters and window, counts original events once, and reads backlog
46
- * through the same choices with an Unset start. It requires `entries` for
46
+ * through the same choices with an Unset start — the Plan's with its window, as
47
+ * one; the Calendar's never, as it pages the backlog through the source itself
48
+ * (#1424), its window reading the window's rows alone. It requires `entries` for
47
49
  * original-key inspection and Save. Existing drafts outside a new narrowing
48
50
  * remain in the session; Save includes them. A kind narrowed so takes no
49
- * `window` or `backlogWindow`.
51
+ * `window` or `backlogWindow`. Every kind counts its events before one is read
52
+ * (`count`, #1039) — through its source, the count its window's read asks
53
+ * first; through its day index, the days' entries the search its read asks
54
+ * first answers; its record read whole, in memory — and the Calendar's and the
55
+ * Plan's builds read its window only within `SCHEDULE_EVENT_CAP`, counted
56
+ * first (#1424). A day index files an event under each day it runs on, so its
57
+ * count is an upper bound on the events, never their number (`countExact`).
58
+ * A builder over resources read a window at a time reads a kind placed on them
59
+ * a cell at a time through the shared schedule reader, which hands each read
60
+ * seam — the events over a window, the backlog, one event by key — what it
61
+ * read of the kind's series index's cells (`cellsType`, `seriesKey`).
50
62
  *
51
63
  * A large record may also be read a window at a time (#1199, `window.ts`): given
52
64
  * `window`, a paged read of a day index keyed by `Schedule.days`, the kind's
@@ -84,30 +96,17 @@ import { EventStateType, TimeStepType } from "@elaraai/east-ui";
84
96
  import { EditingDraftFieldType, EditingReadinessType, Fields, FieldSpecType, TickFormatType } from "@elaraai/east-ui/internal";
85
97
  import { RowInspectorType, rowInspector } from "../utils/row-inspector.js";
86
98
  import { scheduleAccessor } from "./accessor.js";
99
+ import { checkKeyField, fieldOf, fieldSetters, keyFieldRef, keyFieldSlots, keyFieldValue } from "./fields.js";
87
100
  import { SCHEDULE_TEMPLATES, checkedTemplates } from "./templates.js";
88
101
  import { SCHEDULE_DEF } from "./resources.js";
89
- import { scheduleRecordWindow } from "./record-window.js";
102
+ import { SCHEDULE_EVENT_CAP, scheduleRecordCount, scheduleRecordWindow } from "./record-window.js";
90
103
  import { scheduleRecordSession } from "./session.js";
91
- import { checkEntries, checkIndexWindow, optionOf, scheduleBacklogWindow, scheduleDayWindow, typeText } from "./window.js";
104
+ import { checkEntries, checkIndexWindow, optionOf, scheduleBacklogWindow, scheduleDayCount, scheduleDayWindow, typeText } from "./window.js";
92
105
  import { PlanEventItemType, PlanEventKindType, PlanEventReadType, ScheduleAllocationEntryType, ScheduleAllocationKindType, ScheduleAllocationRolesType, ScheduleClockType, ScheduleDraftsType, ScheduleDurationType, ScheduleItemType, ScheduleKindType, ScheduleReadyEntryType, ScheduleResourceRefType, ScheduleRosterEntryType, ScheduleRosterKindType, ScheduleRosterRolesType, ScheduleStatusCasesFor, ScheduleStatusType, ScheduleWriteType, ScheduleTemplateType, ScheduleReadType, } from "./types.js";
93
106
  /** The Roster's roles, as a kind's options name them. */
94
107
  const ROSTER_ROLES = ["shift", "group", "position", "activity", "hours"];
95
108
  /** The Allocation's roles, as a kind's options name them. */
96
109
  const ALLOCATION_ROLES = ["arrival", "parts", "hold", "kind"];
97
- // ============================================================================
98
- // Reading East types
99
- // ============================================================================
100
- /** A variant's cases, when every one of them holds a String. */
101
- function stringCases(type) {
102
- if (type.type !== "Variant" || optionOf(type) !== undefined)
103
- return undefined;
104
- const cases = Object.entries(type.cases);
105
- return cases.length > 0 && cases.every(([, t]) => isTypeEqual(t, StringType)) ? cases.map(([c]) => c) : undefined;
106
- }
107
- /** A field of a struct as an East expression, by name. */
108
- function fieldOf(row, name) {
109
- return row[name];
110
- }
111
110
  /** The ways a kind draws. */
112
111
  const DRAWS = ["span", "buckets", "cards", "marks"];
113
112
  export function scheduleEvents(record, input) {
@@ -183,38 +182,10 @@ export function scheduleEvents(record, input) {
183
182
  ? `${where}: \`backlog\` is a kind's rows with no time, and an instant kind's \`at\` is a plain DateTime field — it has none`
184
183
  : `${where}: \`backlog\` is a kind's rows with no time, and its times are plain DateTime fields — make \`start\` and \`end\` Options for a backlog`);
185
184
  }
186
- let resource;
187
- if (config.resource !== undefined) {
188
- const { field, of } = config.resource;
189
- const type = fieldType("resource.field", field);
190
- const inner = optionOf(type) ?? type;
191
- const isOptional = optionOf(type) !== undefined;
192
- const cases = stringCases(inner);
193
- if (isTypeEqual(inner, StringType)) {
194
- if (typeof of !== "string" || of === "") {
195
- throw new Error(`${where}: \`resource.of\` names the resource slot "${field}" holds keys of — a String field holds one kind's keys`);
196
- }
197
- resource = { field, shape: "key", of, optional: isOptional };
198
- }
199
- else if (cases !== undefined) {
200
- if (typeof of !== "object" || of === null) {
201
- throw new Error(`${where}: "${field}" is a variant — \`resource.of\` names a resource slot per case: { ${cases.map((c) => `${c}: "…"`).join(", ")} }`);
202
- }
203
- const named = Object.keys(of);
204
- if (named.length !== cases.length || !named.every((c) => cases.includes(c))) {
205
- throw new Error(`${where}: \`resource.of\` names a resource slot for each of "${field}"'s cases (${cases.join(", ")}) — and it names ${named.join(", ") || "none"}`);
206
- }
207
- const kinds = Object.values(of);
208
- if (new Set(kinds).size !== kinds.length) {
209
- throw new Error(`${where}: \`resource.of\` names each resource slot once — a case per kind of resource — and it names ${kinds.join(", ")}`);
210
- }
211
- resource = { field, shape: "cases", of, cases, optional: isOptional, variant: inner };
212
- }
213
- else {
214
- throw new Error(`${where}: \`resource.field\` names a field holding a resource's key — a String, a variant of String cases, or an Option of either — and "${field}" holds ${typeText(type)}`);
215
- }
216
- }
217
- const takes = resource === undefined ? [] : resource.shape === "key" ? [resource.of] : Object.values(resource.of);
185
+ // The resource: a key of one kind, or a case per kind (`fields.ts`).
186
+ const resource = config.resource === undefined ? undefined
187
+ : checkKeyField(config.resource.field, fieldType("resource.field", config.resource.field), config.resource.of, { where, prop: "resource", noun: "resource" });
188
+ const takes = resource === undefined ? [] : keyFieldSlots(resource);
218
189
  // The status: a variant, a Status per case.
219
190
  let statusCases;
220
191
  let statusTable;
@@ -348,6 +319,8 @@ export function scheduleEvents(record, input) {
348
319
  // ── The East the seams share ─────────────────────────────────────────
349
320
  const draftType = EditingDraftFieldType(rowType);
350
321
  const EntryRowType = StructType({ id: StringType, key: keyType, row: rowType });
322
+ // The stored entries a reader read by a series index's cells (#1039), each its key and its row.
323
+ const CellsType = ArrayType(StructType({ key: keyType, row: rowType }));
351
324
  // The entry a draft leaves: the drafted entry, none for one deleted, the held one for a draft it cannot read.
352
325
  const drafted = East.function([BlobType, OptionType(rowType)], OptionType(rowType), (_$, bytes, held) => bytes.decodeBeast(draftType, "v2").match({
353
326
  value: (_$2, row) => East.value(some(row), OptionType(rowType)),
@@ -394,6 +367,31 @@ export function scheduleEvents(record, input) {
394
367
  : East.value(some(fieldOf(row, name)), OptionType(DateTimeType));
395
368
  // A time as its field holds it: an Option field holds `some`.
396
369
  const placedAt = (t) => (optional ? East.value(some(t), OptionType(DateTimeType)) : t);
370
+ // How many of the record's stored events overlap [from, to), its record read whole, counted in memory (#1039): by the
371
+ // views' rule, an optional missing end an instant at its start, as the views place it.
372
+ const countWhole = East.function([DateTimeType, DateTimeType], OptionType(IntegerType), ($, from, to) => {
373
+ const all = $.const(readAll());
374
+ const n = $.let(0n, IntegerType);
375
+ $.for(all, ($2, row) => {
376
+ const start = $2.const(instant(row, startField));
377
+ const end = $2.const(instant(row, endField).match({
378
+ none: () => start,
379
+ some: (_$3, e) => East.value(some(e), OptionType(DateTimeType)),
380
+ }));
381
+ $2.match(start, {
382
+ some: ($3, s) => {
383
+ $3.match(end, {
384
+ some: ($4, e) => {
385
+ $4.if(East.less(s, to).and(() => East.greater(e, from).or(() => East.greaterEqual(s, from))), ($5) => {
386
+ $5.assign(n, n.add(1n));
387
+ });
388
+ },
389
+ });
390
+ },
391
+ });
392
+ });
393
+ return East.value(some(n), OptionType(IntegerType));
394
+ });
397
395
  // A duration in minutes — a month counts 30 days.
398
396
  const minutesOf = East.function([ScheduleDurationType], IntegerType, (_$, step) => East.Float.roundHalf(step.match({
399
397
  minutes: (_$2, n) => n,
@@ -406,53 +404,12 @@ export function scheduleEvents(record, input) {
406
404
  : East.function([rowType, keyType], ScheduleDurationType, (_$, row, key) => config.backlog.duration(row, key));
407
405
  const dueOf = config.backlog?.due === undefined ? undefined
408
406
  : East.function([rowType, keyType], OptionType(DateTimeType), (_$, row, key) => config.backlog.due(row, key));
409
- // The resource a row is on.
407
+ // The resource a row is on (`fields.ts`).
410
408
  const RefOption = OptionType(ScheduleResourceRefType);
411
- const refOf = East.function([rowType], RefOption, (_$, row) => {
412
- if (resource === undefined)
413
- return East.value(none, RefOption);
414
- const value = fieldOf(row, resource.field);
415
- if (resource.shape === "key") {
416
- const kind = resource.of;
417
- const ref = (key) => East.value(some(East.value({ kind, key }, ScheduleResourceRefType)), RefOption);
418
- return resource.optional
419
- ? value.match({ none: (_$2) => East.value(none, RefOption), some: (_$2, key) => ref(key) })
420
- : ref(value);
421
- }
422
- const of = resource.of;
423
- const byCase = (v) => v.match(Object.fromEntries(resource.cases.map((c) => [c, (_$2, key) => East.value(some(East.value({ kind: of[c], key }, ScheduleResourceRefType)), RefOption)])));
424
- return resource.optional
425
- ? value.match({ none: (_$2) => East.value(none, RefOption), some: (_$2, v) => byCase(v) })
426
- : byCase(value);
427
- });
409
+ const refOf = keyFieldRef(resource, rowType);
428
410
  // The value a resource field takes for a placement's resource; `none` where the kind refuses it: a resource of a
429
411
  // kind it does not take, or none for a field that must hold one.
430
- const resourceValue = resource === undefined ? undefined : (() => {
431
- const valueType = fields[resource.field];
432
- return East.function([RefOption], OptionType(valueType), ($, ref) => {
433
- const result = $.let(East.value(none, OptionType(valueType)), OptionType(valueType));
434
- $.match(ref, {
435
- none: ($2) => {
436
- if (resource.optional)
437
- $2.assign(result, East.value(some(East.value(none, valueType)), OptionType(valueType)));
438
- },
439
- some: ($2, r) => {
440
- if (resource.shape === "key") {
441
- const key = resource.optional ? East.value(some(r.key), valueType) : r.key;
442
- $2.if(East.equal(r.kind, resource.of), ($3) => { $3.assign(result, East.value(some(key), OptionType(valueType))); });
443
- }
444
- else {
445
- for (const c of resource.cases) {
446
- const caseValue = East.value(variant(c, r.key), resource.variant);
447
- const held = resource.optional ? East.value(some(caseValue), valueType) : caseValue;
448
- $2.if(East.equal(r.kind, resource.of[c]), ($3) => { $3.assign(result, East.value(some(held), OptionType(valueType))); });
449
- }
450
- }
451
- },
452
- });
453
- return result;
454
- });
455
- })();
412
+ const resourceValue = resource === undefined ? undefined : keyFieldValue(resource, fields[resource.field]);
456
413
  // A row of the record's type, field by field: its times and resource from a placement, the rest from `source`.
457
414
  // An instant kind's `at` is its start.
458
415
  const rowWith = (source, start, end, resourceField) => East.value(Object.fromEntries(Object.keys(fields).map((f) => [f,
@@ -476,51 +433,45 @@ export function scheduleEvents(record, input) {
476
433
  return result;
477
434
  });
478
435
  // A setter for every field, at any depth: an inspector edit writes one (`field`), its value as bytes at the field's type.
479
- const setters = [];
480
- const setterOf = (prefix, name, type) => East.function([rowType, BlobType], rowType, (_$, row, bytes) => {
481
- const value = bytes.decodeBeast(type, "v2");
482
- // The structs down the path, each with the field below it replaced, rebuilt from the leaf up.
483
- const chain = [];
484
- let at = row;
485
- let struct = rowType;
486
- for (const step of prefix) {
487
- chain.push({ struct, field: step, at });
488
- at = fieldOf(at, step);
489
- struct = struct.fields[step];
490
- }
491
- const leaf = struct;
492
- const leafAt = at;
493
- let next = East.value(Object.fromEntries(Object.keys(leaf.fields).map((f) => [f, f === name ? value : fieldOf(leafAt, f)])), leaf);
494
- for (let i = chain.length - 1; i >= 0; i--) {
495
- const link = chain[i];
496
- const inner = next;
497
- next = East.value(Object.fromEntries(Object.keys(link.struct.fields).map((f) => [f, f === link.field ? inner : fieldOf(link.at, f)])), link.struct);
498
- }
499
- return next;
500
- });
501
- const collect = (struct, prefix) => {
502
- for (const [name, type] of Object.entries(struct.fields)) {
503
- setters.push({ path: [...prefix, name], set: setterOf(prefix, name, type) });
504
- if (type.type === "Struct")
505
- collect(type, [...prefix, name]);
506
- }
507
- };
508
- collect(rowType, []);
509
- const readsOf = (slot, part) => {
436
+ const setters = fieldSetters(rowType);
437
+ /**
438
+ * The reads, through the kind's source of its builder's slice when it has one — given `cap` (#1039, #1424), the
439
+ * Calendar's and the Plan's, its window counted first, through the source, through its day index or in memory, and
440
+ * read only within `cap`, its backlog whole. Given `pagedBacklog` (#1424, the Calendar's), a kind with a backlog
441
+ * narrowed through its source reads its window's rows alone: its builder pages the backlog through the source itself.
442
+ */
443
+ const readsOf = (slot, part, cap, pagedBacklog = false) => {
510
444
  if (part === undefined) {
511
445
  if (entries !== undefined && dayWindow === undefined) {
512
446
  throw new Error(`${where}: \`entries\` reads one event by its key beside \`window\`, or beside the kind's source of its builder's ` +
513
447
  `Slice.bindRecords (one named "${slot}") — give one of those with it`);
514
448
  }
515
449
  const unscheduled = backlogWindow === undefined ? undefined : scheduleBacklogWindow(backlogWindow, keyType, rowType, where);
450
+ // A backlog index's read takes no window: the window is given, and read past.
451
+ const backlog = unscheduled === undefined ? undefined : East.function([DateTimeType, DateTimeType], OptionType(HeldType), ($, _from, _to) => {
452
+ const read = $.const(unscheduled);
453
+ return read();
454
+ });
455
+ // A record read whole under a cap (#1039): its window counted in memory first, and drawn only within the cap —
456
+ // past it the window answers none, and none of its events draws.
457
+ const capped = cap === undefined || dayWindow !== undefined ? undefined
458
+ : East.function([DateTimeType, DateTimeType], OptionType(HeldType), ($, from, to) => {
459
+ const count = $.const(countWhole);
460
+ const result = $.let(East.value(none, OptionType(HeldType)), OptionType(HeldType));
461
+ $.match(count(from, to), {
462
+ some: ($2, n) => {
463
+ $2.if(n.lessEqual(BigInt(cap)), ($3) => { $3.assign(result, East.value(some(readAll()), OptionType(HeldType))); });
464
+ },
465
+ });
466
+ return result;
467
+ });
516
468
  return {
517
- days: dayWindow === undefined ? undefined : scheduleDayWindow(dayWindow, keyType, rowType, where),
518
- // A backlog index's read takes no window: the window is given, and read past.
519
- backlog: unscheduled === undefined ? undefined : East.function([DateTimeType, DateTimeType], OptionType(HeldType), ($, _from, _to) => {
520
- const read = $.const(unscheduled);
521
- return read();
522
- }),
469
+ // A day index under a cap counts the days' entries first, and past it reads no page (#1039).
470
+ days: dayWindow === undefined ? capped : scheduleDayWindow(dayWindow, keyType, rowType, where, cap),
471
+ backlog,
472
+ alone: backlog,
523
473
  withDrafts: withDraftsFor(false),
474
+ pagedBacklog: false,
524
475
  };
525
476
  }
526
477
  if (dayWindow !== undefined || backlogWindow !== undefined) {
@@ -530,13 +481,20 @@ export function scheduleEvents(record, input) {
530
481
  throw new Error(`${where}: the builder's source "${slot}" reads only its narrowing — and one event, the inspector's ` +
531
482
  "or its editing's, is read by its key: give `entries` beside it, Data.bindPaged(record), the record's own entries");
532
483
  }
533
- const scheduled = scheduleRecordWindow(part, slot, keyType, rowType, startField, endField, optional, false, where);
484
+ const scheduled = scheduleRecordWindow(part, slot, keyType, rowType, startField, endField, optional, false, where, cap);
534
485
  if (!optional)
535
- return { days: scheduled, backlog: undefined, withDrafts: withDraftsFor(true) };
486
+ return { days: scheduled, backlog: undefined, alone: undefined, withDrafts: withDraftsFor(true), pagedBacklog: false };
487
+ const backlogged = scheduleRecordWindow(part, slot, keyType, rowType, startField, endField, optional, true, where);
488
+ if (pagedBacklog) {
489
+ // Its builder pages its backlog through the source itself (#1424): the window is its rows alone, and a draft
490
+ // its host gives draws where it places its event — a backlog event scheduled into the window among them — the
491
+ // host having left out those of events the narrowing does not hold. Its backlog whole is `unscheduled`'s
492
+ // alone, which such a builder never asks.
493
+ return { days: scheduled, backlog: backlogged, alone: backlogged, withDrafts: withDraftsFor(false), pagedBacklog: true };
494
+ }
536
495
  // A kind with a backlog reads both through its source as one: what its narrowing holds over the window and in
537
496
  // its backlog. A draft then moves an event between the two by its times alone, and a draft the narrowing does
538
497
  // not hold never shows in either (#1343).
539
- const backlogged = scheduleRecordWindow(part, slot, keyType, rowType, startField, endField, optional, true, where);
540
498
  const both = East.function([DateTimeType, DateTimeType], OptionType(HeldType), ($, from, to) => {
541
499
  const inWindow = $.const(scheduled);
542
500
  const inBacklog = $.const(backlogged);
@@ -554,7 +512,7 @@ export function scheduleEvents(record, input) {
554
512
  });
555
513
  return result;
556
514
  });
557
- return { days: both, backlog: both, withDrafts: withDraftsFor(true) };
515
+ return { days: both, backlog: both, alone: backlogged, withDrafts: withDraftsFor(true), pagedBacklog: false };
558
516
  };
559
517
  /** An item seam over a window: the events whose items `itemFn` makes that overlap `[from, to)`. */
560
518
  const windowOf = (itemType, itemFn, reads) => East.function([DateTimeType, DateTimeType, ScheduleDraftsType], OptionType(ArrayType(itemType)), ($, from, to, drafts) => {
@@ -622,6 +580,123 @@ export function scheduleEvents(record, input) {
622
580
  }
623
581
  return result;
624
582
  });
583
+ // ── A kind a reader reads by a series index's cells (#1039) ──────────
584
+ // The reader gives the entries it read as one beast2 of `CellsType`; a long event its cells repeat, tile by tile,
585
+ // is one entry, held once by its key. Every draft it gives shows: it gives a draft of an entry it did not read only
586
+ // where its narrowing holds the entry, or the record does not.
587
+ /** The entries a reader read by cells, as the record's rows by key. */
588
+ const cellsHeld = East.function([BlobType], HeldType, ($, bytes) => {
589
+ const entries = $.const(bytes.decodeBeast(CellsType, "v2"));
590
+ const held = $.let(new Map(), HeldType);
591
+ $.for(entries, ($2, entry) => {
592
+ $2(held.insertOrUpdate(entry.key, entry.row, (_$3, _was, now) => now));
593
+ });
594
+ return held;
595
+ });
596
+ /** Every draft given in place over the entries a reader read by cells, as `withDraftsFor` gives them. */
597
+ const cellsInPlace = withDraftsFor(false);
598
+ /** An item seam over the entries a reader read by cells: the events whose items `itemFn` makes that overlap `[from, to)`, by the views' rule. */
599
+ const cellsOf = (itemType, itemFn) => East.function([BlobType, DateTimeType, DateTimeType, ScheduleDraftsType], ArrayType(itemType), ($, bytes, from, to, drafts) => {
600
+ const hold = $.const(cellsHeld);
601
+ const inPlace = $.const(cellsInPlace);
602
+ const item = $.const(itemFn);
603
+ const out = $.let([], ArrayType(itemType));
604
+ $.for(inPlace(hold(bytes), drafts), ($2, entry) => {
605
+ const one = $2.const(item(entry));
606
+ $2.match(one.start, {
607
+ some: ($3, s) => {
608
+ $3.match(one.end, {
609
+ some: ($4, e) => {
610
+ $4.if(East.less(s, to).and(() => East.greater(e, from).or(() => East.greaterEqual(s, from))), ($5) => {
611
+ $5(out.pushLast(one));
612
+ });
613
+ },
614
+ });
615
+ },
616
+ });
617
+ });
618
+ return out;
619
+ });
620
+ /**
621
+ * A backlog seam beside the entries a reader read by cells: the backlog read alone, never the window, with those
622
+ * entries held beside it — a draft moves an event between them by its times alone — the rows with no time, as
623
+ * `itemFn` makes them.
624
+ */
625
+ const backlogBeside = (itemType, itemFn, reads) => East.function([BlobType, DateTimeType, DateTimeType, ScheduleDraftsType], OptionType(ArrayType(itemType)), ($, bytes, from, to, drafts) => {
626
+ const result = $.let(East.value(some([]), OptionType(ArrayType(itemType))), OptionType(ArrayType(itemType)));
627
+ if (optional) {
628
+ const hold = $.const(cellsHeld);
629
+ const inPlace = $.const(cellsInPlace);
630
+ const item = $.const(itemFn);
631
+ let read;
632
+ if (reads.alone === undefined) {
633
+ read = $.let(East.value(some(readAll()), OptionType(HeldType)));
634
+ }
635
+ else {
636
+ const alone = $.const(reads.alone);
637
+ read = $.let(alone(from, to));
638
+ }
639
+ $.assign(result, East.value(none, OptionType(ArrayType(itemType))));
640
+ $.match(read, {
641
+ some: ($2, rows) => {
642
+ const all = $2.let(hold(bytes));
643
+ $2(all.unionInPlace(rows, (_$3, held) => held));
644
+ const out = $2.let([], ArrayType(itemType));
645
+ $2.for(inPlace(all, drafts), ($3, entry) => {
646
+ const one = $3.const(item(entry));
647
+ $3.if(one.start.hasTag("none"), ($4) => { $4(out.pushLast(one)); });
648
+ });
649
+ $2.assign(result, East.value(some(out), OptionType(ArrayType(itemType))));
650
+ },
651
+ });
652
+ }
653
+ return result;
654
+ });
655
+ /**
656
+ * One event by its key's text, the drafts in place, of a kind a reader reads by cells: the drafts, then its row as
657
+ * the reader holds it (`held`, none for one it does not), then the backlog read alone — but where its builder pages
658
+ * the backlog itself (#1424) — then its key; never the window.
659
+ */
660
+ const readBeside = (makeItem, readType, reads) => East.function([StringType, ScheduleDraftsType, DateTimeType, DateTimeType, OptionType(BlobType)], OptionType(readType), ($, id, drafts, from, to, held) => {
661
+ const parse = $.const(keyOf);
662
+ const make = $.const(makeItem);
663
+ const key = $.const(parse(id));
664
+ const row = $.let(East.value(none, OptionType(rowType)), OptionType(rowType));
665
+ const unread = $.let(true, BooleanType);
666
+ $.if(drafts.has(id), ($2) => {
667
+ $2.match(drafts.get(id).decodeBeast(draftType, "v2"), {
668
+ value: ($3, entry) => {
669
+ $3.assign(row, East.value(some(entry), OptionType(rowType)));
670
+ $3.assign(unread, false);
671
+ },
672
+ missing: ($3) => { $3.assign(unread, false); },
673
+ });
674
+ });
675
+ $.if(unread, ($2) => {
676
+ $2.match(held, { some: ($3, bytes) => { $3.assign(row, East.value(some(bytes.decodeBeast(rowType, "v2")), OptionType(rowType))); } });
677
+ // A builder that pages the backlog itself never has it read whole (#1424): its key reads one event.
678
+ if (reads.alone !== undefined && !reads.pagedBacklog) {
679
+ const alone = $2.const(reads.alone);
680
+ $2.if(row.hasTag("none"), ($3) => {
681
+ $3.match(alone(from, to), { some: ($4, rows) => { $4.assign(row, rows.tryGet(key)); } });
682
+ });
683
+ }
684
+ if (byKey === undefined) {
685
+ const all = $2.const(readAll());
686
+ $2.if(row.hasTag("none"), ($3) => { $3.assign(row, all.tryGet(key)); });
687
+ }
688
+ else {
689
+ const find = $2.const(byKey);
690
+ $2.if(row.hasTag("none"), ($3) => {
691
+ $3.match(find(id), { held: ($4, stored) => { $4.assign(row, East.value(some(stored), OptionType(rowType))); } });
692
+ });
693
+ }
694
+ });
695
+ return row.match({
696
+ some: (_$2, r) => East.value(some({ item: make({ id, key, row: r }), row: East.Blob.encodeBeast(r, "v2") }), OptionType(readType)),
697
+ none: (_$2) => East.value(none, OptionType(readType)),
698
+ });
699
+ });
625
700
  const readEvent = (makeItem, readType, reads) => East.function([StringType, ScheduleDraftsType, DateTimeType, DateTimeType], OptionType(readType), ($, id, drafts, from, to) => {
626
701
  const parse = $.const(keyOf);
627
702
  const make = $.const(makeItem);
@@ -645,7 +720,8 @@ export function scheduleEvents(record, input) {
645
720
  }
646
721
  const days = $2.const(reads.days);
647
722
  $2.match(days(from, to), { some: ($3, held) => { $3.assign(row, held.tryGet(key)); } });
648
- if (reads.backlog !== undefined) {
723
+ // A builder that pages the backlog itself never has it read whole (#1424): its key reads one event.
724
+ if (reads.backlog !== undefined && !reads.pagedBacklog) {
649
725
  const backlog = $2.const(reads.backlog);
650
726
  $2.if(row.hasTag("none"), ($3) => {
651
727
  $3.match(backlog(from, to), { some: ($4, held) => { $4.assign(row, held.tryGet(key)); } });
@@ -661,12 +737,114 @@ export function scheduleEvents(record, input) {
661
737
  none: (_$2) => East.value(none, OptionType(readType)),
662
738
  });
663
739
  });
740
+ /**
741
+ * A kind's three read seams over its events as `itemFn` makes them (#1039): its events over a window, its backlog,
742
+ * and one event by its key — each from what a reader read by its series index's cells when it is given that, and
743
+ * never the window then; else over the window, as `reads` reads it.
744
+ */
745
+ const readSeams = (itemType, itemFn, readType, reads) => {
746
+ const window = windowOf(itemType, itemFn, reads);
747
+ const cells = cellsOf(itemType, itemFn);
748
+ const items = East.function([DateTimeType, DateTimeType, ScheduleDraftsType, OptionType(BlobType)], OptionType(ArrayType(itemType)), ($, from, to, drafts, read) => {
749
+ const overWindow = $.const(window);
750
+ const fromCells = $.const(cells);
751
+ return read.match({
752
+ none: (_$2) => overWindow(from, to, drafts),
753
+ some: (_$2, bytes) => East.value(some(fromCells(bytes, from, to, drafts)), OptionType(ArrayType(itemType))),
754
+ });
755
+ });
756
+ const backlog = backlogOf(itemType, itemFn, reads);
757
+ const besideCells = backlogBeside(itemType, itemFn, reads);
758
+ const unscheduled = East.function([DateTimeType, DateTimeType, ScheduleDraftsType, OptionType(BlobType)], OptionType(ArrayType(itemType)), ($, from, to, drafts, read) => {
759
+ const overWindow = $.const(backlog);
760
+ const beside = $.const(besideCells);
761
+ return read.match({
762
+ none: (_$2) => overWindow(from, to, drafts),
763
+ some: (_$2, bytes) => beside(bytes, from, to, drafts),
764
+ });
765
+ });
766
+ const windowed = readEvent(itemFn, readType, reads);
767
+ const besideRead = readBeside(itemFn, readType, reads);
768
+ const event = East.function([StringType, ScheduleDraftsType, DateTimeType, DateTimeType, OptionType(OptionType(BlobType))], OptionType(readType), ($, id, drafts, from, to, held) => {
769
+ const overWindow = $.const(windowed);
770
+ const byCells = $.const(besideRead);
771
+ return held.match({
772
+ none: (_$2) => overWindow(id, drafts, from, to),
773
+ some: (_$2, row) => byCells(id, drafts, from, to, row),
774
+ });
775
+ });
776
+ return { items, unscheduled, event };
777
+ };
778
+ /**
779
+ * A kind's events' rows over a window and its backlog's beside them, by key, the drafts in place, read once (#1409,
780
+ * R24): the reads `event` finds one row in — the window's rows, then the backlog's where it is read apart from them —
781
+ * as the record's own Dict's bytes, so a run's request finds every event's row there rather than reading them all
782
+ * again an event. `none` while a read is in flight. It reads the window, never a reader's cells: a kind read by them
783
+ * carries no request.
784
+ */
785
+ const rowsOver = (reads) => {
786
+ // A backlog read apart from the window's rows — a backlog index's, beside a day index — is read beside them; one
787
+ // read through the kind's source is read with them, and a record read whole holds it already.
788
+ const apart = reads.backlog !== undefined && !Object.is(reads.backlog, reads.days) && !reads.pagedBacklog;
789
+ // The entries held, the drafts in place, as the record's own Dict, by key: its bytes.
790
+ const heldBytes = East.function([ArrayType(EntryRowType)], BlobType, ($, entries) => {
791
+ const out = $.let(new Map(), HeldType);
792
+ $.for(entries, ($2, entry) => { $2(out.insert(entry.key, entry.row)); });
793
+ return East.Blob.encodeBeast(out, "v2");
794
+ });
795
+ return East.function([DateTimeType, DateTimeType, ScheduleDraftsType], OptionType(BlobType), ($, from, to, drafts) => {
796
+ const inPlace = $.const(reads.withDrafts);
797
+ const bytesOf = $.const(heldBytes);
798
+ const result = $.let(East.value(none, OptionType(BlobType)), OptionType(BlobType));
799
+ let read;
800
+ if (reads.days === undefined) {
801
+ read = $.let(East.value(some(readAll()), OptionType(HeldType)));
802
+ }
803
+ else {
804
+ const days = $.const(reads.days);
805
+ read = $.let(days(from, to));
806
+ }
807
+ $.match(read, {
808
+ some: ($2, rows) => {
809
+ if (!apart) {
810
+ $2.assign(result, East.value(some(bytesOf(inPlace(rows, drafts))), OptionType(BlobType)));
811
+ return;
812
+ }
813
+ const backlog = $2.const(reads.backlog);
814
+ $2.match(backlog(from, to), {
815
+ some: ($3, more) => {
816
+ const all = $3.let(rows.copy());
817
+ $3(all.unionInPlace(more, (_$4, held) => held));
818
+ $3.assign(result, East.value(some(bytesOf(inPlace(all, drafts))), OptionType(BlobType)));
819
+ },
820
+ });
821
+ },
822
+ });
823
+ return result;
824
+ });
825
+ };
826
+ // The `.east` text of the value the resource field holds for a resource, or for none: what a series or a summary
827
+ // index of the record files the resource's events under (#1039), the key a reader's cells search for.
828
+ const seriesKey = East.function([RefOption], OptionType(StringType), ($, ref) => {
829
+ const result = $.let(none, OptionType(StringType));
830
+ if (resourceValue !== undefined) {
831
+ const resolve = $.const(resourceValue);
832
+ $.match(resolve(ref), { some: ($2, value) => { $2.assign(result, some(East.print(value))); } });
833
+ }
834
+ return result;
835
+ });
664
836
  /**
665
837
  * The Calendar's kind, part by part, under its slot and through its source's part, its form `form` — and the
666
- * function that makes one of its events.
838
+ * function that makes one of its events. Given `cap`, its window — through its source, through its day index or in
839
+ * memory, its record read whole — is counted first and read only within it (#1039, #1424): the Calendar's and the
840
+ * Plan's. Every kind is counted before one of its events is read (`count`), through its source's interval index —
841
+ * the count its window's read asks first, so none of its own — through its day index, the days' entries the search
842
+ * its window's read asks first answers (an upper bound, never their number: `countExact` false), or in memory. Given
843
+ * `pagedBacklog` (#1424, the Calendar's), a kind with a backlog narrowed through its source reads its window's rows
844
+ * alone, its builder paging the backlog through the source itself.
667
845
  */
668
- const kindParts = (slot, part, form) => {
669
- const reads = readsOf(slot, part);
846
+ const kindParts = (slot, part, form, cap, pagedBacklog = false) => {
847
+ const reads = readsOf(slot, part, cap, pagedBacklog);
670
848
  // One event, as every view draws it.
671
849
  const itemOf = East.function([EntryRowType], ScheduleItemType, ($, entry) => {
672
850
  const row = entry.row;
@@ -711,8 +889,13 @@ export function scheduleEvents(record, input) {
711
889
  due,
712
890
  }, ScheduleItemType);
713
891
  });
714
- const items = windowOf(ScheduleItemType, itemOf, reads);
715
- const unscheduled = backlogOf(ScheduleItemType, itemOf, reads);
892
+ const seams = readSeams(ScheduleItemType, itemOf, ScheduleReadType, reads);
893
+ // How many of its stored events overlap [from, to), counted before one is read (#1039): through its source's
894
+ // interval index — the count its window's read asks first, so none of its own; through its day index, the days'
895
+ // entries the search its window's read asks first answers — an event under each day it runs on, so an upper
896
+ // bound on them, never their number; or, its record read whole, in memory, by the views' rule.
897
+ const count = part !== undefined ? scheduleRecordCount(part, slot, keyType, rowType, startField, endField, optional, where)
898
+ : dayWindow !== undefined ? scheduleDayCount(dayWindow, where) : countWhole;
716
899
  // Each template's values, by key, as the templates on the wire carry them.
717
900
  const templateRows = boundTemplates ?? East.value(templates.map((t) => ({
718
901
  key: t.key, name: t.name, group: t.group === undefined ? none : some(t.group),
@@ -803,20 +986,25 @@ export function scheduleEvents(record, input) {
803
986
  templates: templateRows,
804
987
  templatesSource: templatesSource === undefined ? none : some(templatesSource),
805
988
  fields: East.value(form, ArrayType(FieldSpecType)),
806
- items,
807
- unscheduled,
989
+ items: seams.items,
990
+ unscheduled: seams.unscheduled,
808
991
  write,
809
992
  ready: ready === undefined ? none : some(ready),
810
993
  editing,
811
994
  entries: entriesSeam,
812
995
  history: session.history,
813
- event: readEvent(itemOf, ScheduleReadType, reads),
996
+ event: seams.event,
814
997
  // A kind with no title names none: the Calendar and Plan, whose inspectors draw it, refuse one.
815
998
  schedule: { title: titleField ?? "", start: startField, end: endField,
816
999
  resource: resource === undefined ? none : some(resource.field),
817
1000
  status: config.status === undefined ? none : some(config.status.field) },
818
1001
  overlaps: variant(overlaps, null),
819
1002
  inspector: inspector === undefined ? none : some(inspector),
1003
+ seriesKey,
1004
+ cellsType: toEastTypeValue(CellsType),
1005
+ count,
1006
+ // Every count but a day index's counts the events themselves.
1007
+ countExact: part !== undefined || dayWindow === undefined,
820
1008
  };
821
1009
  return { fields: fieldsOfKind, itemOf, reads };
822
1010
  };
@@ -886,8 +1074,13 @@ export function scheduleEvents(record, input) {
886
1074
  roles: [...rosterGiven, ...allocationGiven],
887
1075
  partsOf: config.parts?.of,
888
1076
  allocationValues,
1077
+ times: { start: startField, end: endField },
1078
+ resourceField: resource?.field,
1079
+ windowed: dayWindow !== undefined,
889
1080
  build(slot, part) {
890
- return East.value(kindParts(slot, part, formSpecs).fields, ScheduleKindType);
1081
+ // Its window counted first, and read only within the cap (#1424): past it, no page is read. The Calendar pages
1082
+ // a narrowed kind's backlog through its source itself, so its window reads the window's rows alone.
1083
+ return East.value(kindParts(slot, part, formSpecs, SCHEDULE_EVENT_CAP, true).fields, ScheduleKindType);
891
1084
  },
892
1085
  buildRoster(slot, part) {
893
1086
  // A duty runs from its start to its end, keyed by String, on its slot's shift and group, rostered to someone.
@@ -1066,7 +1259,8 @@ export function scheduleEvents(record, input) {
1066
1259
  }, ScheduleAllocationKindType);
1067
1260
  },
1068
1261
  buildPlan(slot, part) {
1069
- const parts = kindParts(slot, part, formSpecs);
1262
+ // Its window through its source counted first, and read only within the cap (#1039): past it, no page is read.
1263
+ const parts = kindParts(slot, part, formSpecs, SCHEDULE_EVENT_CAP);
1070
1264
  const quantity = config.quantity;
1071
1265
  const format = quantity?.format === undefined ? undefined : East.value(quantity.format, TickFormatType);
1072
1266
  // One event as Plan draws it: what every view draws, with its roles read from their fields.
@@ -1087,12 +1281,10 @@ export function scheduleEvents(record, input) {
1087
1281
  lane: laneField === undefined ? none : some(fieldOf(row, laneField)),
1088
1282
  }, PlanEventItemType);
1089
1283
  });
1090
- // One event by its id, the drafts in place: as Plan draws it, and its row as bytes. A draft holds its
1091
- // event as drafted, or says it was deleted; an event never drafted — or one whose draft can't be read —
1092
- // is the record's: read whole, or for a kind read a window at a time (#1199) looked for first among the
1093
- // rows its windows hold over [from, to) and its backlog's, where a gesture's event is drawn, then read
1094
- // by its key.
1095
- const planEvent = readEvent(planItemOf, PlanEventReadType, parts.reads);
1284
+ // One event by its id, the drafts in place, as Plan draws it, and its events and its backlog as Plan draws
1285
+ // them: the kind's three read seams over its own item (`readSeams`) — a kind a reader reads by its series
1286
+ // index's cells (#1039) given what it read, and never reading the window.
1287
+ const plan = readSeams(PlanEventItemType, planItemOf, PlanEventReadType, parts.reads);
1096
1288
  const name = (field) => (field === undefined ? none : some(field));
1097
1289
  return East.value({
1098
1290
  ...parts.fields,
@@ -1100,9 +1292,11 @@ export function scheduleEvents(record, input) {
1100
1292
  instant: instantKind,
1101
1293
  overlaps: variant(overlaps, null),
1102
1294
  roles: { state: name(stateField), quantity: name(quantityField), lane: name(laneField) },
1103
- planItems: windowOf(PlanEventItemType, planItemOf, parts.reads),
1104
- planUnscheduled: backlogOf(PlanEventItemType, planItemOf, parts.reads),
1105
- planEvent,
1295
+ planItems: plan.items,
1296
+ planUnscheduled: plan.unscheduled,
1297
+ planEvent: plan.event,
1298
+ // Every event's row at once, for a run's request (#1409, R24): read once, never once an event.
1299
+ planRows: rowsOver(parts.reads),
1106
1300
  inspector: inspector === undefined ? East.value(none, OptionType(RowInspectorType)) : East.value(some(inspector), OptionType(RowInspectorType)),
1107
1301
  }, PlanEventKindType);
1108
1302
  },