@@ -250,7 +250,6 @@ func (c *Core) updateCurrentChild(updated *Event) (*Event, error) {
250250 if ! ok || parent == nil || ! parent .IsParent () {
251251 return nil , fmt .Errorf ("no valid parent found" )
252252 }
253-
254253 if parent .Repeat == nil {
255254 return nil , fmt .Errorf ("parent is not a repeating event, WTF" )
256255 }
@@ -270,83 +269,110 @@ func (c *Core) updateCurrentChild(updated *Event) (*Event, error) {
270269 return c .CreateEvent (detachedEvent ) // save as new
271270}
272271
273- // Splits the time series into two by stopping the original parent event from repeating further and creating brand new parent with updated properties.
272+ // updateFollowingChildren splits the time series into two by stopping the original parent event from repeating further and creating brand new parent with updated properties.
274273func (c * Core ) updateFollowingChildren (old , new * Event ) (* Event , error ) {
275- parent , ok := c .events [new .ParentId ]
274+ parent , ok := c .events [old .ParentId ]
276275 if ! ok || parent == nil || ! parent .IsParent () {
277276 return nil , fmt .Errorf ("no valid parent found" )
278277 }
278+ if parent .Repeat == nil {
279+ return nil , fmt .Errorf ("parent is not a repeating event" )
280+ }
279281
280- // save originals for rollback
282+ // keep originals for rollback
281283 originalRepeat := * parent .Repeat
282- originalExceptions := append ([]uuid.UUID {}, parent .Repeat .Exceptions ... ) // deep copy
284+ originalExceptions := append ([]uuid.UUID (nil ), parent .Repeat .Exceptions ... )
285+
286+ // find position in the series
287+ _ , splitIndex := firstOccurrenceAtOrAfter (old .From , parent )
288+ if splitIndex == - 1 {
289+ return nil , fmt .Errorf ("could not find occurrence at or after %s" , old .From )
290+ }
291+
292+ fromDiff := new .From .Sub (old .From )
293+
294+ // editing the first occurrence -> update entire series
295+ if splitIndex == 0 {
296+ return c .updateAllChildren (old , new )
297+ }
298+
299+ // split exceptions before and after the edited occurrence
300+ exBefore , exAfter := splitExceptions (originalExceptions , old .From )
301+
302+ // remove parent before we mutate it
303+ if err := c .intervalTree .RemoveEvent (* parent ); err != nil {
304+ return nil , fmt .Errorf ("failed to remove parent from interval tree: %w" , err )
305+ }
283306
284- until := addUnit (old .From , - 1 , old .Repeat .Frequency ) // cap parent at start of change
285- if ! until .After (parent .From ) {
307+ // ------------ cap the original parent ------------
308+ previousStart := addUnit (old .From , - originalRepeat .Interval , originalRepeat .Frequency )
309+ if ! previousStart .After (parent .From ) {
310+ // only one occurrence left -> turn it into a basic (non-repeating) event
286311 parent .Repeat = nil
287312 } else {
288- parent .Repeat .Until = until
289- parent .Repeat .Count = 0 // enforce Until logic over Count
313+ // keep repeating but stop before the split point
314+ capped := originalRepeat
315+ capped .Until = previousStart
316+ capped .Count = 0
317+ capped .Exceptions = exBefore
318+ parent .Repeat = & capped
290319 }
291320
292- // split exceptions
293- exBefore , exAfter := splitExceptions (originalExceptions , new .From )
294- if parent .Repeat != nil {
295- parent .Repeat .Exceptions = exBefore
321+ // save the capped parent
322+ if err := c .intervalTree .InsertEvent (* parent ); err != nil {
323+ parent .Repeat = & originalRepeat
324+ parent .Repeat .Exceptions = originalExceptions
325+ return nil , fmt .Errorf ("failed to reinsert capped parent: %w" , err )
296326 }
297327
298328 if err := c .saveAndCommitEvent (parent , fmt .Sprintf ("Capped parent event %q" , parent .Id )); err != nil {
299- return nil , fmt .Errorf ("failed to commit parent event: %w" , err )
300- }
301-
302- // create the new parent for the second half of the time series
303- newEvent := * new // shallow copy
304- newEvent .Id = uuid .New () // assign new id
305- newEvent .ParentId = uuid .Nil // not child anymore
306-
307- if originalRepeat .Count != 0 && newEvent .Repeat != nil {
308- // shorten the repeat for the second half
309- _ , elapsed := firstOccurrenceAtOrAfter (old .From , parent )
310- if elapsed <= 0 {
311- // the split is at the first occurance -> nothing to subtract (basically update all)
312- newEvent .Repeat .Count = originalRepeat .Count
313- } else {
314- remaining := originalRepeat .Count - elapsed
315- if remaining <= 0 {
329+ return nil , fmt .Errorf ("failed to commit capped parent: %w" , err )
330+ }
331+
332+ // ------------ create the new continuing series ------------
333+ newEvent := * new
334+ newEvent .Id = uuid .New ()
335+ newEvent .ParentId = uuid .Nil // this is now its own parent
336+
337+ if newEvent .Repeat != nil {
338+ repeat := * newEvent .Repeat
339+ repeat .Exceptions = nil
340+
341+ // adjust count for remaining occurrences
342+ if originalRepeat .Count != 0 {
343+ remaining := originalRepeat .Count - splitIndex
344+ if remaining < 1 {
316345 remaining = 1
317346 }
318- newEvent . Repeat .Count = remaining
347+ repeat .Count = remaining
319348 }
320- }
321349
322- // transform exceptions
323- fromDiff := newEvent .From .Sub (old .From )
324- if fromDiff != 0 {
325- for _ , exc := range exAfter {
326- t := getTimeFromUUID (exc )
327- t = t .Add (fromDiff )
328- newEvent .Repeat .Exceptions = append (newEvent .Repeat .Exceptions , generateCustomUUID (newEvent .Id , t ))
329- }
330- }
331- if newEvent .Repeat != nil && newEvent .Repeat .Count != 0 {
332- newEvent .Repeat .Count -= len (exAfter )
333- if newEvent .Repeat .Count < 1 {
334- newEvent .Repeat .Count = 1
350+ // shift exceptions to the new parent
351+ for _ , ex := range exAfter {
352+ exTime := getTimeFromUUID (ex ).Add (fromDiff )
353+ repeat .Exceptions = append (repeat .Exceptions , generateCustomUUID (newEvent .Id , exTime ))
335354 }
355+
356+ newEvent .Repeat = & repeat
336357 }
337358
338- createdEvent , err := c .CreateEvent (newEvent )
359+ created , err := c .CreateEvent (newEvent )
339360 if err != nil {
340- // rollback the parent cap
361+ // rollback: restore original parent
362+ _ = c .intervalTree .RemoveEvent (* parent )
341363 parent .Repeat = & originalRepeat
342364 parent .Repeat .Exceptions = originalExceptions
343- if rbErr := c .saveAndCommitEvent (parent , fmt .Sprintf ("Rolled back cap on parent event %q" , parent .Id )); rbErr != nil {
344- return nil , fmt .Errorf ("failed to create new event: %w; rollback also failed: %v" , err , rbErr )
365+
366+ if rbErr := c .intervalTree .InsertEvent (* parent ); rbErr != nil {
367+ return nil , fmt .Errorf ("failed to create new series: %w; rollback failed too: %v" , err , rbErr )
368+ }
369+ if rbErr := c .saveAndCommitEvent (parent , fmt .Sprintf ("rolled back parent %q" , parent .Id )); rbErr != nil {
370+ return nil , fmt .Errorf ("failed to create new series: %w; rollback failed too: %v" , err , rbErr )
345371 }
346- return nil , fmt .Errorf ("failed to create new event : %w" , err )
372+ return nil , fmt .Errorf ("failed to create new continuing series : %w" , err )
347373 }
348374
349- return createdEvent , nil
375+ return created , nil
350376}
351377
352378// Updates the entire repeating series by only modifying the parent. That means all generated child events get updated as well.
0 commit comments