Object set definition via function that accepts self as input?

I have a rather complex object set definition problem that I cannot figure out a solution for. The following uses notional data to depict the problem:

I have a list of Flanker Runs that have a one to many relation with Flanker Update ontologies. When selected in the table on the left, I want to automatically choose the most recent Flanker Update (based on a timestamp property associated with each Flanker Update) and add it to a list of Updates that populate the table on the right.

Next, I want to be able to click on one of the Flanker Runs in the left table (active select not the multi-select checkbox) and have all of the linked Flanker Updates appear in the filter - single select - box on the bottom left.

When I choose an update from that filter, I want the table on the left to reflect the correct update. That is, if no update is selected in the bottom left the table should give the most recent update and if there is an update selected it should replace it with the chosen. BUT there can only be one update selected per parent.

I tried to create an object set definition based on a typescript function that I setup to do this. The code for the function is is as follows:

@Function()
public finalFlankerUpdates(previousUpdates:ObjectSet,
activeFlankerRuns:ObjectSet,
selectedUpdate:ObjectSet):
ObjectSet{

          // Function to return the most recent update of a flanker run
          function recentUpdate(flanker_run:FlankerRun){ 
              let updates = flanker_run.flankerUpdate.all(); 
              let next = updates[0]; 
              for (let i=0; i<updates.length; i++){ 
                  if (updates[i].timeStamp! > next.timeStamp!){ 
                      next = updates[i]; 
                  }
              }
              return next
          };

          // Check the list of previous updates against the activeFlankerRuns to see if updates need to be removed or added 
          let previousRuns = previousUpdates.searchAroundFlankerRun();

          // Remove any updates from the previous list if their parent's are no longer in the activeRun list
          let finalUpdates = previousUpdates.subtract(previousRuns.subtract(activeFlankerRuns).searchAroundFlankerUpdate()); 

          // Grab any new parents that weren't in the previous list
          let newParents = activeFlankerRuns.subtract(previousRuns).all()

          // Add most recent update if there is a flankerRun in the active list that is not in the previous list
          let update:ObjectSet<FlankerUpdate>
          for (let i=0; i<newParents.length; i++){
              update = Objects.search().flankerUpdate().filter(object => object.flankerUpdateId.exactMatch(recentUpdate(newParents[i]).flankerUpdateId)); 
              finalUpdates = finalUpdates.union(update);
          }

          // Check for updates in the list that have the same parent as the selected update and replace
          if (selectedUpdate.all().length > 0){  
              let updateParent = selectedUpdate.searchAroundFlankerRun().all()[0];
              let duplicate = Objects.search().flankerUpdate().filter(object => object.flankerRunId.exactMatch(updateParent.flankerRunId))
              finalUpdates = finalUpdates.subtract(duplicate).union(selectedUpdate);
          } 
          return finalUpdates
  }

The problem that I am running into is that I don’t have a way to monitor the current items in the list which is what I was trying to do by passing the previous list, but I was getting a circular dependence error when trying to set this up in workshop.

Is there a way to specify a function that takes the variable itself as an input argument to achieve the behavior that I am looking for? Any other suggestions for how to accomplish this would be greatly helpful!

Thanks
-BP

Hey @brianpatrick3, Workshop currently prevents variable dependency cycles so that users don’t end up configuring cycles that never resolve.

I can appreciate that this safeguard may prevent some valid use cases where you could ensure yourself there will never be a cycles that never settles.

I’ll think some more if I can suggest an alternative setup here, but a common workaround I’ve seen is to at some point in the cycle introduce a user action with the “Set variable value” event to break the cycle. You may be able to do this by having something like an “Apply” button which copies the current value to a separate “previousValue” variable. Since the user “Apply” action is required for this copying, there is no automatic variable dependency cycle.

Does this sound like it could work for your use case?

@evanj

Thank you for the quick reply. The solution you provided would work, but requires more user interaction than we would like. The issue being that if the user forgets to click “Apply” and moves on to selecting another update, the list tracking the previous selection will not reflect the information that the user intended and will result in the final list of objects being incorrect.

Is there a way to automatically track when an object set variable changes and perform the same event that would update the “previousValue” object set? This might be the next best solution if it is possible. If it requires some user interaction through a button click or other action, I may have to modify our setup to get the desired behavior.

If you happen to think of any other possible solutions, I would greatly appreciate it!

Thanks,
-BP

EDIT: This is the same solution that Evan suggested above. Apologies for the double up. I’ll leave it here anyway.

Assuming the Flanker and Flanker Update objects are backed by datasources and pipelines and their properties don’t change dynamically (for example, Flanker Updates are not user-created or updated), one option might be to add the Selected Flanker Update as a property (a foreign key) of the Flanker object in it’s backing pipeline, which defaults to the latest update, then have an Action which updates this to the particular update selected from your bottom left view.

Your table would then just be showing the selected Flankers’ Selected Flanker Update by following the link. As the user overwrites this with their choices that will automatically reflect in the table.