Skip to content
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

Cpk bidirectional #1751

Merged
merged 4 commits into from
May 26, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"id": "3d128fdd-17a8-45ea-a166-44f6712b86f4",
"modelSchema": {
"name": "Blog",
"modelSchemaVersion": 0,
"pluralName": "Blogs",
"authRules": [],
"fields": {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
{
"serializedData": {
"post": {
"id": "11e2e7b8-0535-47d5-ad34-072a5fa2ca7d",
"title": "May 20th 10:29 post"
},
"title": "Comment title",
"content": "Content",
"likes": 2
},
"id": "\"Comment title\"#\"Content\"#\"2\"",
"modelSchema": {
"associations": {
"post": {
"targetNames": [],
"targetName": "postCommentsId",
"name": "BelongsTo",
"associatedName": "post",
"associatedType": "Post"
}
},
"pluralName": "Comments",
"authRules": [],
"indexes": {
"undefined": {
"indexName": "undefined",
"indexFieldNames": [
"title",
"content",
"likes"
]
}
},
"modelClass": "com.amplifyframework.testmodels.customprimarykey.Comment",
"name": "Comment",
"modelSchemaVersion": 1,
"modelType": "USER",
"fields": {
"createdAt": {
"javaClassForValue": "com.amplifyframework.core.model.temporal.Temporal$DateTime",
"isRequired": false,
"isCustomType": false,
"isReadOnly": true,
"isModel": false,
"authRules": [],
"name": "createdAt",
"isEnum": false,
"targetType": "AWSDateTime",
"isArray": false
},
"post": {
"javaClassForValue": "com.amplifyframework.testmodels.customprimarykey.Post",
"isRequired": false,
"isCustomType": false,
"isReadOnly": false,
"isModel": true,
"authRules": [],
"name": "post",
"isEnum": false,
"targetType": "Post",
"isArray": false
},
"description": {
"javaClassForValue": "java.lang.String",
"isRequired": false,
"isCustomType": false,
"isReadOnly": false,
"isModel": false,
"authRules": [],
"name": "description",
"isEnum": false,
"targetType": "String",
"isArray": false
},
"title": {
"javaClassForValue": "java.lang.String",
"isRequired": true,
"isCustomType": false,
"isReadOnly": false,
"isModel": false,
"authRules": [],
"name": "title",
"isEnum": false,
"targetType": "String",
"isArray": false
},
"content": {
"javaClassForValue": "java.lang.String",
"isRequired": true,
"isCustomType": false,
"isReadOnly": false,
"isModel": false,
"authRules": [],
"name": "content",
"isEnum": false,
"targetType": "String",
"isArray": false
},
"likes": {
"javaClassForValue": "java.lang.Integer",
"isRequired": true,
"isCustomType": false,
"isReadOnly": false,
"isModel": false,
"authRules": [],
"name": "likes",
"isEnum": false,
"targetType": "Int",
"isArray": false
},
"updatedAt": {
"javaClassForValue": "com.amplifyframework.core.model.temporal.Temporal$DateTime",
"isRequired": false,
"isCustomType": false,
"isReadOnly": true,
"isModel": false,
"authRules": [],
"name": "updatedAt",
"isEnum": false,
"targetType": "AWSDateTime",
"isArray": false
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"id": "970f1b78-8786-4762-a43a-17c70f966684",
"modelSchema": {
"name": "Meeting",
"modelSchemaVersion": 0,
"pluralName": "Meetings",
"authRules": [],
"fields": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,12 +147,14 @@ private void recurseTree(
if (childSchema.getPrimaryIndexFields().size() > 1) {
childFields.addAll(childSchema.getPrimaryIndexFields());
}
parentId = childSchema.getAssociations() // get a map of associations
.get(association.getAssociatedName()) // get @BelongsTo association linked to this field
.getTargetName(); // get the target field (parent) name
parentId = SQLiteTable.getForeignKeyColumnName(childSchema.getVersion(),
// get a map of associations
association.getAssociatedName(), childSchema.getAssociations()
// get the target field (parent) name
.get(association.getAssociatedName()));
} catch (NullPointerException unexpectedAssociation) {
LOG.warn("Foreign key was not found due to unidirectional relationship without @BelongsTo. " +
"Failed to publish cascading mutations.",
LOG.warn("Foreign key was not found due to unidirectional relationship without " +
"@BelongsTo. " + "Failed to publish cascading mutations.",
unexpectedAssociation);
return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -378,7 +378,7 @@ public <T extends Model> void save(
} catch (DataStoreException dataStoreException) {
onError.accept(dataStoreException);
} catch (Exception someOtherTypeOfException) {
String modelToString = item.getModelName() + "[id=" + item.getPrimaryKeyString() + "]";
String modelToString = item.getModelName() + "[primaryKey =" + item.getPrimaryKeyString() + "]";
DataStoreException dataStoreException = new DataStoreException(
"Error in saving the model: " + modelToString,
someOtherTypeOfException, "See attached exception for details."
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ public static SQLiteTable fromSchema(@NonNull ModelSchema modelSchema) {
// All associated fields are also foreign keys at this point
SQLiteColumn column = SQLiteColumn.builder()
.name(isAssociated
? association.getTargetName()
? getForeignKeyColumnName(modelSchema.getVersion(), modelField.getName(), association)
: modelField.getName())
.fieldName(modelField.getName())
.tableName(modelSchema.getName())
Expand Down Expand Up @@ -214,6 +214,24 @@ public String getPrimaryKeyColumnName() {
return getPrimaryKey().getQuotedColumnName();
}

/**
* Returns the column name of foreign key for the associated field passed in.
* @param schemaVersion int
* @param fieldName String associated filedName ModelAssociation association
* @param association ModelAssociation
* @return the column name of foreign key
*/
@NonNull
public static String getForeignKeyColumnName(int schemaVersion, String fieldName, ModelAssociation association) {
if (schemaVersion == 0) {
return association.getTargetName();
}
if (association.getTargetNames().length > 1) {
return "@@" + fieldName + "ForeignKey";
}
return association.getTargetNames()[0];
}

/**
* Returns the list of foreign keys of this table.
* @return the list of foreign keys of this table
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ public int hashCode() {

// A has one-to-many relationship with B
@SuppressWarnings("checkstyle:all")
@ModelConfig(type = Model.Type.USER, version = 1)
private class A extends TestModel {
@ModelField(targetType = "ID") private final String id;
@ModelField(targetType = "B") @HasMany(associatedWith = "a", type = B.class) private List<B> b;
Expand All @@ -160,32 +161,34 @@ private class A extends TestModel {
// B has one-to-many relationship with C
// B belongs to A
@SuppressWarnings("checkstyle:all")
@ModelConfig(type = Model.Type.USER, version = 1)
private class B extends TestModel {
@ModelField(targetType = "ID") private final String id;
@ModelField(targetType = "C") @HasMany(associatedWith = "b", type = C.class) private List<C> c;
@ModelField(targetType = "A") @BelongsTo(targetName = "aId", type = A.class) private A a;
@ModelField(targetType = "A") @BelongsTo(targetNames = {"aId"}, type = A.class) private A a;
@NonNull public String resolveIdentifier() { return id; }
private B(int id) { this.id = Integer.toString(id); }
}

// C belongs to B
@SuppressWarnings("checkstyle:all")
@ModelConfig(type = Model.Type.USER, version = 1)
private class C extends TestModel {
@ModelField(targetType = "ID") private final String id;
@ModelField(targetType = "B") @BelongsTo(targetName = "bId", type = B.class) private B b;
@ModelField(targetType = "B") @BelongsTo(targetNames = {"bId"}, type = B.class) private B b;
@ModelField(targetType = "D") @HasMany(associatedWith = "c", type = D.class) private List<D> d;
@NonNull public String resolveIdentifier() { return id; }
private C(int id) { this.id = Integer.toString(id); }
}

// C belongs to B
@SuppressWarnings("checkstyle:all")
@ModelConfig(type = Model.Type.USER)
@ModelConfig(type = Model.Type.USER, version = 1)
@Index(name = "undefined", fields = {"name","title"})
private class D extends TestModel {
@ModelField(targetType = "String") private final String name;
@ModelField(targetType = "String") private final String title;
@ModelField(targetType = "C") @BelongsTo(targetName = "cId", type = C.class) private C c;
@ModelField(targetType = "C") @BelongsTo(targetNames = {"cId"}, type = C.class) private C c;
@NonNull public DPrimaryKey resolveIdentifier() { return new DPrimaryKey(name, title); }
private D(String name, String title) {
this.name = name;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import com.amplifyframework.core.model.ModelSchema;
import com.amplifyframework.datastore.storage.sqlite.SQLiteDataType;
import com.amplifyframework.testmodels.commentsblog.Post;
import com.amplifyframework.testmodels.customprimarykey.Comment;

import org.junit.Test;

Expand Down Expand Up @@ -91,4 +92,82 @@ public void createSQLiteTableForPost() throws AmplifyException {
assertEquals(expected, actual);
assertEquals("id", actual.getPrimaryKey().getFieldName());
}

/**
* Test if a {@link ModelSchema} for {@link com.amplifyframework.testmodels.customprimarykey.Comment}
* returns an expected {@link SQLiteTable}. This tests the general
* use case, for an object with most data types (String, Integer, enum, BelongsTo, and HasMany relationships).
* @throws AmplifyException on error deriving ModelSchema.
*/
@Test
public void createSQLiteTableForaModelWithParentHavingCPK() throws AmplifyException {
ModelSchema schema = ModelSchema.fromModelClass(Comment.class);
Map<String, SQLiteColumn> columns = new HashMap<>();
columns.put("title", SQLiteColumn.builder()
.name("title")
.fieldName("title")
.dataType(SQLiteDataType.TEXT)
.isNonNull(true)
.tableName("Comment")
.build());
columns.put("post", SQLiteColumn.builder()
.name("@@postForeignKey")
.fieldName("post")
.dataType(SQLiteDataType.TEXT)
.isNonNull(false)
.tableName("Comment")
.ownerOf("Post")
.build());
columns.put("@@primaryKey", SQLiteColumn.builder()
.name("@@primaryKey")
.fieldName("@@primaryKey")
.dataType(SQLiteDataType.TEXT)
.isNonNull(true)
.tableName("Comment")
.build());
columns.put("description", SQLiteColumn.builder()
.name("description")
.fieldName("description")
.dataType(SQLiteDataType.TEXT)
.isNonNull(false)
.tableName("Comment")
.build());
columns.put("content", SQLiteColumn.builder()
.name("content")
.fieldName("content")
.dataType(SQLiteDataType.TEXT)
.isNonNull(true)
.tableName("Comment")
.build());
columns.put("likes", SQLiteColumn.builder()
.name("likes")
.fieldName("likes")
.dataType(SQLiteDataType.INTEGER)
.isNonNull(true)
.tableName("Comment")
.build());
columns.put("updatedAt", SQLiteColumn.builder()
.name("updatedAt")
.fieldName("updatedAt")
.dataType(SQLiteDataType.TEXT)
.isNonNull(false)
.tableName("Comment")
.build());
columns.put("createdAt", SQLiteColumn.builder()
.name("createdAt")
.fieldName("createdAt")
.dataType(SQLiteDataType.TEXT)
.isNonNull(false)
.tableName("Comment")
.build());

SQLiteTable expected = SQLiteTable.builder()
.columns(columns)
.name("Comment")
.build();

SQLiteTable actual = SQLiteTable.fromSchema(schema);
assertEquals(expected, actual);
assertEquals("@@primaryKey", actual.getPrimaryKey().getFieldName());
}
}
Loading