palantir-foundrypalantir-foundry-api

Palantir Foundry: Composite-Key for DataSet-Rows / Object-Instance Primary Key


I have a one-to-many Ontology relationship where -- for a given Alert object-instance -- I want at most one Feedback object-instance for it per User. A Feedback object-instance is Created & Updated by Users using its Add & Modify Actions, respectively (and is used to provide one feedback score & commentary per User per Alert object-instance).

As such, to implement at most one semantics, each Feedback object requires a Primary Key composed of:

feedbackID (PK) = alertID (PK) + userID (PK)

However, in its backend definition, the Feedback object-type's Add Action sets the Primary Key as a UUID, and this cannot be overwritten once instantiated. (Note: An object-reference or property is also possible here, but either would also only be part of the composite key sought). That is to say, although it's possible to synthesize the above composite-key in a frontend Workshop Action Tab (using Workshop variables and forms), it's understandably not possible to overwrite an object's already-existing PK with it.

Indicentally, for completeness, I'll mention, but not necessarily recommend, a two-DataSet option for composite-key PK consisting of the following steps:

  1. The Add Action creates rows for an initial DataSet with UUID's as its PK.
  2. A Foundry data pipeline mirrors this DataSet to create a corresponding DataSet with alertID + userID as its PK.
  3. And finally, the Modify Action as well as downstream application uses consume that mirror (second) DataSet.

Again, presented for completeness and not necessarily recommended since it duplicates DataSets, as well as adds propagation delay to the out-of-the-box platform propagation delay.

With that as preamble, is there a just-in-time technique to generate Objects with a composite-key PK consisting of properties from other Objects (again, at Add-Action click time)? I may have missed something. Thank you.


Solution

  • I came up with an interim workaround which broadly include these steps:

    1. If 0 is returned, only the Add Action Button (in green) is visible (via display logic).
    2. If 1 is returned, only the Modify Action Button (in amber) is visible (via display logic).
    3. If > 1 is returned (which would only happen if a bug existed somewhere), only a Red Error Button is visible (via display logic), with its hover-over text instructing the user to take a screenshot and eMail developers. No Action or Event is attached to this button.
    @Function() // Used to set a Workshop variable (0|1|>1).
    public async countFeedbackRecords(alertID: string,
                                      userID: string):
                                      Promise<Integer> {
    
      const feedbacks = Objects.search().feedback() // Feedback object-type is imported at top-of-file.
      const count = await feedbacks.filter(obj => obj.alertId.exactMatch(alertID))
                                   .filter(obj => obj.user.exactMatch(userID))
                                   .count()
    
      return Promise.resolve(count || 0)
    }
    

    One downside to this approach are lookups against the two columns mentioned, which are neither hashed nor indexed.