Skip to content

Commit

Permalink
Merge pull request #370 from gfx/embedded_type_as_foreign_key
Browse files Browse the repository at this point in the history
Embedded type as foreign key
  • Loading branch information
gfx authored Jan 25, 2017
2 parents 60e678a + c006b5f commit 74e4891
Show file tree
Hide file tree
Showing 6 changed files with 145 additions and 16 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/*
* Copyright (c) 2015 FUJI Goro (gfx).
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.github.gfx.android.orma.test;

import com.github.gfx.android.orma.ModelFactory;
import com.github.gfx.android.orma.test.model.ModelWithCustomPrimaryKey;
import com.github.gfx.android.orma.test.model.OrmaDatabase;
import com.github.gfx.android.orma.test.toolbox.EnumA;
import com.github.gfx.android.orma.test.toolbox.OrmaFactory;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;

import android.support.annotation.NonNull;
import android.support.test.runner.AndroidJUnit4;

import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;

@RunWith(AndroidJUnit4.class)
public class PrimaryKeyWithTypeAdapterTest {

OrmaDatabase db;

@Before
public void setUp() throws Exception {
db = OrmaFactory.create();
}

@Test
public void bigIntegerPrimaryKey() throws Exception {
final ModelWithCustomPrimaryKey model = db
.createModelWithCustomPrimaryKey(new ModelFactory<ModelWithCustomPrimaryKey>() {
@NonNull
@Override
public ModelWithCustomPrimaryKey call() {
return ModelWithCustomPrimaryKey.create(EnumA.FOO);
}
});

ModelWithCustomPrimaryKey.Holder holder = db.createHolder(new ModelFactory<ModelWithCustomPrimaryKey.Holder>() {
@NonNull
@Override
public ModelWithCustomPrimaryKey.Holder call() {
ModelWithCustomPrimaryKey.Holder holder = new ModelWithCustomPrimaryKey.Holder();
holder.object = model;
return holder;
}
});

assertThat(holder.object.id, is(EnumA.FOO));

assertThat(db.selectFromHolder().objectEq(EnumA.FOO).value().object.id, is(EnumA.FOO));
assertThat(db.selectFromHolder().objectEq(model).value().object.id, is(EnumA.FOO));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import com.github.gfx.android.orma.Schema;
import com.github.gfx.android.orma.test.model.Author_Schema;
import com.github.gfx.android.orma.test.model.Book_Schema;
import com.github.gfx.android.orma.test.model.Holder_Schema;
import com.github.gfx.android.orma.test.model.ModelWithCompositeIndex_Schema;
import com.github.gfx.android.orma.test.model.ModelWithDirectAssociation2_Schema;
import com.github.gfx.android.orma.test.model.ModelWithDirectAssociation_Schema;
Expand Down Expand Up @@ -200,4 +201,9 @@ public void compositeIndexes() throws Exception {

));
}

@Test
public void foreignKeyType() throws Exception {
assertThat(Holder_Schema.INSTANCE.object.storageType, is("INTEGER"));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* Copyright (c) 2015 FUJI Goro (gfx).
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.github.gfx.android.orma.test.model;

import com.github.gfx.android.orma.annotation.Column;
import com.github.gfx.android.orma.annotation.PrimaryKey;
import com.github.gfx.android.orma.annotation.Table;
import com.github.gfx.android.orma.test.toolbox.EnumA;

// https://github.com/gfx/Android-Orma/issues/368
@Table
public class ModelWithCustomPrimaryKey {

@PrimaryKey
public EnumA id;

public static ModelWithCustomPrimaryKey create(EnumA id) {
ModelWithCustomPrimaryKey model = new ModelWithCustomPrimaryKey();
model.id = id;
return model;
}

@Table
public static class Holder {

@PrimaryKey
public long id;

@Column(indexed = true)
public ModelWithCustomPrimaryKey object;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -113,11 +113,9 @@ CodeBlock serializedFieldExpr(ColumnDefinition column, ParameterSpec paramSpec)
.orElseThrow(() -> new ProcessingException(
"Missing @PrimaryKey for " + associatedSchema.getModelClassName().simpleName(),
associatedSchema.getElement()));
return CodeBlock.builder()
.add("$L /* primary key */", primaryKey.buildGetColumnExpr(paramSpec.name))
.build();
return primaryKey.buildSerializedColumnExpr("conn", paramSpec.name);
} else {
return column.buildSerializeExpr("conn", paramSpec.name);
return column.applySerialization("conn", paramSpec.name);
}

}
Expand Down Expand Up @@ -190,6 +188,7 @@ void buildConditionHelpersForEachColumn(List<MethodSpec> methodSpecs, ColumnDefi
SchemaDefinition associatedSchema = column.getAssociatedSchema();
associatedSchema.getPrimaryKey().ifPresent(foreignKey -> {
String paramName = column.name + Strings.toUpperFirst(foreignKey.name);
CodeBlock serializedParamExpr = foreignKey.applySerialization("conn", paramName);
methodSpecs.add(
MethodSpec.methodBuilder(column.name + "Eq")
.addModifiers(Modifier.PUBLIC)
Expand All @@ -198,7 +197,7 @@ void buildConditionHelpersForEachColumn(List<MethodSpec> methodSpecs, ColumnDefi
.addAnnotations(foreignKey.nullabilityAnnotations())
.build())
.returns(targetClassName)
.addStatement("return where($L, $S, $L)", columnExpr, "=", paramName)
.addStatement("return where($L, $S, $L)", columnExpr, "=", serializedParamExpr)
.build()
);
});
Expand Down Expand Up @@ -227,7 +226,7 @@ void buildConditionHelpersForEachColumn(List<MethodSpec> methodSpecs, ColumnDefi
.addModifiers(Modifier.PUBLIC)
.returns(column.getSerializedBoxType())
.addParameter(ParameterSpec.builder(type.box(), "value").build())
.addStatement("return $L", column.buildSerializeExpr("conn", "value"))
.addStatement("return $L", column.applySerialization("conn", "value"))
.build())
.build();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ public List<MethodSpec> buildMethodSpecs() {
.beginControlFlow("else");
}
methodSpecBuilder.addStatement("contents.put($S, $L)", column.getEscapedColumnName(),
column.buildSerializeExpr("conn", paramName));
column.applySerialization("conn", paramName));
if (column.isNullableInJava()) {
methodSpecBuilder.endControlFlow();
}
Expand Down Expand Up @@ -155,7 +155,7 @@ public List<MethodSpec> buildMethodSpecs() {
)
.addStatement("contents.put($S, $L)",
column.getEscapedColumnName(),
primaryKey.buildGetColumnExpr(column.name))
primaryKey.buildSerializedColumnExpr("conn", column.name))
.addStatement("return this")
.build()
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ private static String extractStorageType(ProcessingContext context, TypeName typ
return SqlTypes.getSqliteType(TypeName.LONG);
} else if (Types.isDirectAssociation(context, type)) {
return context.getSchemaDef(type).getPrimaryKey()
.map(primaryKey -> SqlTypes.getSqliteType(primaryKey.getType()))
.map(primaryKey -> SqlTypes.getSqliteType(primaryKey.getSerializedType()))
.orElseGet(() -> {
context.addError("Missing @PrimaryKey as foreign key", element);
return "UNKNOWN";
Expand Down Expand Up @@ -326,29 +326,36 @@ public CodeBlock buildGetColumnExpr(CodeBlock modelExpr) {
}

public CodeBlock buildSerializedColumnExpr(String connectionExpr, String modelExpr) {
return buildSerializedColumnExpr(connectionExpr, CodeBlock.of("$L", modelExpr));
}

public CodeBlock buildSerializedColumnExpr(String connectionExpr, CodeBlock modelExpr) {
CodeBlock getColumnExpr = buildGetColumnExpr(modelExpr);

if (isSingleAssociation()) {
return CodeBlock.of("$L.getId()", getColumnExpr);
} else if (isDirectAssociation()) {
return getAssociatedSchema().getPrimaryKey()
.map(primaryKey -> primaryKey.buildGetColumnExpr(getColumnExpr))
.map(primaryKey -> primaryKey.buildSerializedColumnExpr(connectionExpr, getColumnExpr))
.orElseGet(() -> CodeBlock.of("null /* missing @PrimaryKey */"));
} else if (needsTypeAdapter()) {
return buildSerializeExpr(connectionExpr, getColumnExpr);
} else {
return getColumnExpr;
return applySerialization(connectionExpr, getColumnExpr);
}
}

public CodeBlock buildSerializeExpr(String connectionExpr, String valueExpr) {
return buildSerializeExpr(connectionExpr, CodeBlock.of("$L", valueExpr));
public CodeBlock applySerialization(String connectionExpr, String valueExpr) {
return applySerialization(connectionExpr, CodeBlock.of("$L", valueExpr));
}

public CodeBlock buildSerializeExpr(String connectionExpr, CodeBlock valueExpr) {
public CodeBlock applySerialization(String connectionExpr, CodeBlock valueExpr) {
// TODO: parameter injection for static type serializers
if (needsTypeAdapter()) {
if (typeAdapter == null) {
if (isAssociation()) {
throw new AssertionError("[BUG] applySerialization() called for "
+ schema.getModelClassName() + "#" + name);
}

throw new ProcessingException("Missing @StaticTypeAdapter to serialize " + type, element);
}

Expand Down

0 comments on commit 74e4891

Please sign in to comment.