Skip to content

Commit

Permalink
update
Browse files Browse the repository at this point in the history
  • Loading branch information
mfriesen committed Jun 10, 2024
1 parent 6c3423a commit 1a754b9
Show file tree
Hide file tree
Showing 11 changed files with 301 additions and 165 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@

/**
*
* DynamoDB Keys.
* DynamoDB Record.
*
* @param <T> Type of DynamodbRecord
*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
/**
* MIT License
*
* Copyright (c) 2018 - 2020 FormKiQ
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.formkiq.aws.dynamodb;

import com.formkiq.aws.dynamodb.objects.DateUtil;
import software.amazon.awssdk.services.dynamodb.model.AttributeValue;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static com.formkiq.aws.dynamodb.DbKeys.GSI1_PK;
import static com.formkiq.aws.dynamodb.DbKeys.GSI1_SK;
import static com.formkiq.aws.dynamodb.DbKeys.GSI2_PK;
import static com.formkiq.aws.dynamodb.DbKeys.GSI2_SK;
import static com.formkiq.aws.dynamodb.DbKeys.PK;
import static com.formkiq.aws.dynamodb.DbKeys.SK;

/**
* Versioned {@link DynamodbRecord}.
*
* @param <T> Type of DynamodbRecord
*/
public interface DynamodbVersionRecord<T> extends DynamodbRecord<T> {

/** Archive Key Prefix. */
String ARCHIVE_KEY_PREFIX = "Archive";

/**
* Get DynamoDb versioning PK.
*
* @param siteId {@link String}
* @return {@link String}
*/
String pkVersion(String siteId);

/**
* Get DynamoDb versioning SK.
*
* @return {@link String}
*/
String skVersion();

/**
* Get Inserted Date {@link String}.
*
* @return {@link String}
*/
default String getInsertedDate() {
SimpleDateFormat df = DateUtil.getIsoDateFormatter();
return df.format(new Date());
}

/**
* Update Attributes to Version.
*
* @param siteId {@link String}
* @param attrs {@link Map}
* @return {@link Map}
*/
default Map<String, AttributeValue> updateAttributesToVersioned(final String siteId,
final Map<String, AttributeValue> attrs) {

Map<String, AttributeValue> updated = new HashMap<>(attrs);

for (String key : List.of(PK, SK, GSI1_PK, GSI1_SK, GSI2_PK, GSI2_SK)) {
if (attrs.containsKey(key)) {
updated.put(ARCHIVE_KEY_PREFIX + key, attrs.get(key));
}
}

updated.put(PK, AttributeValue.fromS(pkVersion(siteId)));
updated.put(SK, AttributeValue.fromS(skVersion()));

return updated;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -103,22 +103,12 @@ public interface DocumentService extends DocumentTagLoader {
* @param attributeKey {@link String}
* @param validation {@link AttributeValidation}
* @param validationAccess {@link AttributeValidationAccess}
* @return boolean
* @throws ValidationException ValidationException
*/
boolean deleteDocumentAttribute(String siteId, String documentId, String attributeKey,
AttributeValidation validation, AttributeValidationAccess validationAccess)
throws ValidationException;

/**
* Delete Document Attributes.
*
* @param siteId {@link String}
* @param documentId {@link String}
* @return boolean
* @return {@link List} {@link DocumentAttributeRecord}
* @throws ValidationException ValidationException
*/
boolean deleteDocumentAttributes(String siteId, String documentId) throws ValidationException;
List<DocumentAttributeRecord> deleteDocumentAttribute(String siteId, String documentId,
String attributeKey, AttributeValidation validation,
AttributeValidationAccess validationAccess) throws ValidationException;

/**
* Delete Document Attribute Value.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -258,28 +258,32 @@ private void appendDocumentAttributes(final WriteRequestBuilder writeBuilder, fi
Map<String, AttributeRecord> attributeMap = validateDocumentAttributes(schema, siteId,
documentId, documentAttributes, isUpdate, validation, validationAccess);

for (AttributeRecord attribute : attributeMap.values()) {
if (!attribute.isInUse()) {
this.attributeService.setInUse(siteId, attribute.getKey());
}
}
// update Attributes to In-Use
attributeMap.values().stream().filter(a -> !a.isInUse())
.forEach(a -> this.attributeService.setInUse(siteId, a.getKey()));

// when updating attributes remove existing attribute keys
if (AttributeValidationAccess.ADMIN_UPDATE.equals(validationAccess)
|| AttributeValidationAccess.UPDATE.equals(validationAccess)) {

List<String> attributeKeys =
documentAttributes.stream().map(DocumentAttributeRecord::getKey).toList();

for (String attributeKey : attributeKeys) {
deleteDocumentAttribute(siteId, documentId, attributeKey, AttributeValidation.NONE,
AttributeValidationAccess.NONE);
List<DocumentAttributeRecord> deletedValues = deleteDocumentAttribute(siteId, documentId,
attributeKey, AttributeValidation.NONE, AttributeValidationAccess.NONE);

this.versionsService.addRecords(dbClient, siteId, deletedValues);
}
}

// when setting attributes remove existing attribute
if (AttributeValidationAccess.ADMIN_SET.equals(validationAccess)
|| AttributeValidationAccess.SET.equals(validationAccess)) {
deleteDocumentAttributes(siteId, documentId, validationAccess);

List<DocumentAttributeRecord> deletedValues =
deleteDocumentAttributes(siteId, documentId, validationAccess);
this.versionsService.addRecords(dbClient, siteId, deletedValues);
}

writeBuilder.appends(this.documentTableName,
Expand Down Expand Up @@ -433,8 +437,8 @@ public boolean deleteDocument(final String siteId, final String documentId,
}

@Override
public boolean deleteDocumentAttribute(final String siteId, final String documentId,
final String attributeKey, final AttributeValidation validation,
public List<DocumentAttributeRecord> deleteDocumentAttribute(final String siteId,
final String documentId, final String attributeKey, final AttributeValidation validation,
final AttributeValidationAccess validationAccess) throws ValidationException {

if (!AttributeValidation.NONE.equals(validation)) {
Expand All @@ -446,28 +450,19 @@ public boolean deleteDocumentAttribute(final String siteId, final String documen
}
}

final int limit = 100;
DocumentAttributeRecord r =
new DocumentAttributeRecord().documentId(documentId).key(attributeKey);

QueryConfig config = new QueryConfig();
QueryResponse response = this.dbService.queryBeginsWith(config, r.fromS(r.pk(siteId)),
r.fromS(ATTR + attributeKey + "#"), null, limit);
List<DocumentAttributeRecord> documentAttributes =
findDocumentAttribute(siteId, documentId, attributeKey);

List<Map<String, AttributeValue>> keys =
response.items().stream().map(a -> Map.of(PK, a.get(PK), SK, a.get(SK))).toList();
List<Map<String, AttributeValue>> keys = documentAttributes.stream()
.map(a -> Map.of(PK, a.fromS(a.pk(siteId)), SK, a.fromS(a.sk()))).toList();
this.dbService.deleteItems(keys);

return this.dbService.deleteItems(keys);
return documentAttributes;
}

@Override
public boolean deleteDocumentAttributes(final String siteId, final String documentId)
private List<DocumentAttributeRecord> deleteDocumentAttributes(final String siteId,
final String documentId, final AttributeValidationAccess validationAccess)
throws ValidationException {
return deleteDocumentAttributes(siteId, documentId, null);
}

private boolean deleteDocumentAttributes(final String siteId, final String documentId,
final AttributeValidationAccess validationAccess) throws ValidationException {

final int limit = 100;
DocumentAttributeRecord r = new DocumentAttributeRecord().documentId(documentId);
Expand All @@ -476,7 +471,11 @@ private boolean deleteDocumentAttributes(final String siteId, final String docum
QueryResponse response =
this.dbService.queryBeginsWith(config, r.fromS(r.pk(siteId)), r.fromS(ATTR), null, limit);

List<DocumentAttributeRecord> documentAttributes = response.items().stream()
.map(a -> new DocumentAttributeRecord().getFromAttributes(siteId, a)).toList();

if (AttributeValidationAccess.SET.equals(validationAccess)) {

List<String> attributeKeys = response.items().stream().map(a -> a.get("key").s()).toList();

Map<String, AttributeRecord> attributes =
Expand All @@ -485,7 +484,7 @@ private boolean deleteDocumentAttributes(final String siteId, final String docum
Optional<AttributeRecord> o =
attributes.values().stream().filter(a -> AttributeType.OPA.equals(a.getType())).findAny();

if (!o.isEmpty()) {
if (o.isPresent()) {
String key = o.get().getKey();
String error = "Cannot remove attribute '" + key + "' type OPA";
throw new ValidationException(
Expand All @@ -496,7 +495,8 @@ private boolean deleteDocumentAttributes(final String siteId, final String docum
List<Map<String, AttributeValue>> keys =
response.items().stream().map(a -> Map.of(PK, a.get(PK), SK, a.get(SK))).toList();

return this.dbService.deleteItems(keys);
this.dbService.deleteItems(keys);
return documentAttributes;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,10 @@
*/
package com.formkiq.stacks.dynamodb;

import java.util.Collection;
import java.util.Map;
import com.formkiq.aws.dynamodb.DynamoDbConnectionBuilder;
import com.formkiq.aws.dynamodb.DynamodbVersionRecord;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import software.amazon.awssdk.services.dynamodb.model.AttributeValue;

Expand Down Expand Up @@ -92,4 +94,14 @@ String getVersionId(DynamoDbConnectionBuilder connection, String siteId, String
*/
void revertDocumentVersionAttributes(Map<String, AttributeValue> previous,
Map<String, AttributeValue> current);

/**
* Add Versioning {@link DynamodbVersionRecord} records.
*
* @param client {@link DynamoDbClient}
* @param siteId {@link String}
* @param records {@link Collection} {@link DynamodbVersionRecord}
*/
void addRecords(DynamoDbClient client, String siteId,
Collection<? extends DynamodbVersionRecord<?>> records);
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,14 @@
import static com.formkiq.aws.dynamodb.SiteIdKeyGenerator.createDatabaseKey;
import static software.amazon.awssdk.utils.StringUtils.isEmpty;
import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;
import com.formkiq.aws.dynamodb.DynamoDbConnectionBuilder;
import com.formkiq.aws.dynamodb.DynamoDbService;
import com.formkiq.aws.dynamodb.DynamoDbServiceImpl;
import com.formkiq.aws.dynamodb.DynamodbVersionRecord;
import com.formkiq.aws.dynamodb.QueryConfig;
import com.formkiq.aws.dynamodb.objects.DateUtil;
import com.formkiq.graalvm.annotations.Reflectable;
Expand All @@ -54,7 +56,7 @@ public class DocumentVersionServiceDynamoDb implements DocumentVersionService {
/** The Default maximum results returned. */
private static final int MAX_RESULTS = 100;
/** {@link SimpleDateFormat} in ISO Standard format. */
private SimpleDateFormat df = DateUtil.getIsoDateFormatter();
private final SimpleDateFormat df = DateUtil.getIsoDateFormatter();
/** DynamoDB Document Versions Table Name. */
private String tableName = null;

Expand Down Expand Up @@ -107,12 +109,6 @@ public String getDocumentVersionsTableName() {
return this.tableName;
}

private String getSk(final Map<String, AttributeValue> previous, final String version) {
String sk = previous.get(SK).s() + TAG_DELIMINATOR + this.df.format(new Date())
+ TAG_DELIMINATOR + "v" + version;
return sk;
}

@Override
public String getVersionId(final DynamoDbConnectionBuilder connection, final String siteId,
final String documentId, final String versionKey) {
Expand Down Expand Up @@ -155,4 +151,21 @@ public void revertDocumentVersionAttributes(final Map<String, AttributeValue> pr
String sk = getSk(current, current.get(VERSION_ATTRIBUTE).s());
current.put(SK, AttributeValue.fromS(sk));
}

@Override
public void addRecords(final DynamoDbClient client, final String siteId,
final Collection<? extends DynamodbVersionRecord<?>> records) {

List<Map<String, AttributeValue>> attrs =
records.stream().map(r -> r.getAttributes(siteId)).toList();

DynamoDbService db = new DynamoDbServiceImpl(client, getDocumentVersionsTableName());
db.putItems(attrs);
}

private String getSk(final Map<String, AttributeValue> previous, final String version) {
String sk = previous.get(SK).s() + TAG_DELIMINATOR + this.df.format(new Date())
+ TAG_DELIMINATOR + "v" + version;
return sk;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,10 @@
*/
package com.formkiq.stacks.dynamodb;

import java.util.Collection;
import java.util.Map;
import com.formkiq.aws.dynamodb.DynamoDbConnectionBuilder;
import com.formkiq.aws.dynamodb.DynamodbVersionRecord;
import com.formkiq.graalvm.annotations.Reflectable;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
Expand Down Expand Up @@ -70,4 +72,10 @@ public void revertDocumentVersionAttributes(final Map<String, AttributeValue> pr
final Map<String, AttributeValue> current) {
// empty
}

@Override
public void addRecords(final DynamoDbClient client, final String siteId,
final Collection<? extends DynamodbVersionRecord<?>> records) {
// empty
}
}
Loading

0 comments on commit 1a754b9

Please sign in to comment.