-
Notifications
You must be signed in to change notification settings - Fork 59
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(assets): Add create API with insert to fail on duplicates #498
base: master
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Solid PR, but a few high-level questions and potential gaps
(Ebean)LocalAccess
is never directly invoked by themetadata-graph-assets
service:
assetModelPegasusInterop.getPegasusAspectsFromAsset(asset).stream()
.forEach(aspect -> dao.add((URN) pegasusUrn, aspect, auditStamp, pegasusTrackingContext, pegasusParams));
It only has access to (Ebean)LocalDAO
, through which LocalAccess is invoked:
EbeanLocalDAO.java
:
public <ASPECT extends RecordTemplate> void updateEntityTables(@Nonnull URN urn, @Nonnull Class<ASPECT> aspectClass) {
...
ASPECT aspect = toRecordTemplate(aspectClass, result).orElse(null);
_localAccess.add(urn, aspect, aspectClass, auditStamp, null, false);
...
I believe you will probably need to introduce a new set of methods inside EbeanLocalDao.java
-- and / or perhaps BaseLocalDao.java
-- in order to access the functionality here.
- Design choice of adding a new method (done here in this PR) vs adding a flag for existing functionality
This is more of a question than a comment, but is there a reason that CREATE functionality is being added as a new method here as opposed to just adding a boolean flag
or something to other existing add()
methods?
At a cursory glance it seems like other than the SQL statement used, the logic flow is basically identical.
Maybe you've thought through future augmentations / feature-adds that are needed and it needs to be separate or something similar?
- Ingestion callback requirements?
Do you know if Ingestion Callback will be needed for CREATE? If you aren't sure what this is, @ZihanLi58 / I / Yihong can explain the concept -- and Zihan can probably elaborate on the need -- but basically this is something supported by Normal Ingestion at the moment and is implemented at the DAO (not Access) level.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you share more requirement about the create API? basically
is it for createAsset or createAspect?
If createAsset, then I think you might need to accept more aspects in one request?
If createAspect, then we probably only want to fail the request when the urn and the aspect are all existing? If urn exist but aspect does not, we should still create it for user?
dao-impl/ebean-dao/src/main/java/com/linkedin/metadata/dao/EbeanLocalAccess.java
Outdated
Show resolved
Hide resolved
Based on the question I ask before, you can choose different design choice there. And to make sure the ingestion behavior is consistency, call back is required for create as well |
@ZihanLi58 please review. thanks! |
@kotkar-pallavi Current update api actually accept asset as input, and it does the upsert for each aspect Iteratively. In your current approach, can the create user facing api take asset as input? If the asset contains multiple aspect, it seems will fail the request right as second create call for second aspect will fail since the first one already create the urn. |
dao-api/src/main/java/com/linkedin/metadata/dao/BaseLocalDAO.java
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Other than Zihan's comment, lgtm from me
maxTransactionRetry); | ||
|
||
// skip MAE producing and post update hook in test mode or if the result is null (no actual update with addCommon) | ||
return ingestionParams.isTestMode() ? result.newValue : unwrapAddResult(urn, result, auditStamp, trackingContext); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IIUC, CREATE
will return the NEW value of the Asset after it (successfully) runs?
dao-impl/ebean-dao/src/test/java/com/linkedin/metadata/dao/EbeanLocalAccessTest.java
Show resolved
Hide resolved
@ZihanLi58 updated to create aspects with multiple aspects. it will be done in a single create statement that will throw exception if urn already exists. as discussed offline, doing a exists check followed by iterative create might lead to race condition. please re-review. thanks! |
dao-api/src/main/java/com/linkedin/metadata/dao/BaseLocalDAO.java
Outdated
Show resolved
Hide resolved
dao-api/src/main/java/com/linkedin/metadata/dao/BaseLocalDAO.java
Outdated
Show resolved
Hide resolved
dao-impl/ebean-dao/src/main/java/com/linkedin/metadata/dao/EbeanLocalDAO.java
Outdated
Show resolved
Hide resolved
dao-impl/ebean-dao/src/main/java/com/linkedin/metadata/dao/EbeanLocalAccess.java
Show resolved
Hide resolved
} | ||
|
||
String metadata = String.join(",", auditedAspects); | ||
return sqlUpdate.setParameter("metadata", metadata).execute(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is the intention to replace :metadata with values (separated with comma) from multiple columns?
INSERT INTO table(urn, a_urn, column1, column2) VALUE (:urn, :a_urn, :metadata)
and
update.setParameter("metadata", "a, b");
I suspect if this is allowed, can you double check? and add an unit test for it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes :metadata
will have comma separated values. it is difficult to test and I tried adding unit test here: a59095e
from debugging with breakpoint, i verified the values and they look as follows:
{"lastmodifiedon":"2025-02-23 23:13:29.767","aspect":{"value":"foo"},"lastmodifiedby":"urn:li:testActor:actor","canonicalName":"com.linkedin.testing.AspectFoo"},{"lastmodifiedon":"2025-02-23 23:13:29.767","aspect":{"value":"bar"},"lastmodifiedby":"urn:li:testActor:actor","canonicalName":"com.linkedin.testing.AspectBar"}
It has comma separated value for aspect foo and bar.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Logic looks good to me, but seems a lot useless code, can you do a clean up?
Summary
Testing Done
Local build and added unit tests
Checklist