diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..e8dddf6 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,7 @@ +# Change Log + +## Version 0.4.0 (11-27-2014) + +- Added query builder functionality. Returned from `selectFrom` +- Removed namespacing on tables. All tables MUST have unique names. +- Create statements written out. \ No newline at end of file diff --git a/README.md b/README.md index bee717e..5567cd5 100644 --- a/README.md +++ b/README.md @@ -62,19 +62,19 @@ jar in your application compile time. You can download the jars com.andrewreitz shillelagh - 0.3.0 + 0.4.0 com.andrewreitz shillelagh-processor - 0.3.0 + 0.4.0 true ``` ## Gradle: ```groovy - compile 'com.andrewreitz:shillelagh:0.3.0' - provided 'com.andrewreitz:shillelagh:0.3.0' + compile 'com.andrewreitz:shillelagh:0.4.0' + provided 'com.andrewreitz:shillelagh:0.4.0' ``` # License diff --git a/build.gradle b/build.gradle index 06a03bf..1adfcbd 100644 --- a/build.gradle +++ b/build.gradle @@ -22,7 +22,7 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:0.14.0' + classpath 'com.android.tools.build:gradle:0.14.1' classpath 'com.netflix.nebula:gradle-extra-configurations-plugin:1.12.3' classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:0.6' classpath 'org.jfrog.buildinfo:build-info-extractor-gradle:3.0.1' diff --git a/shillelagh-processor/src/main/java/shillelagh/internal/ShillelaghProcessor.java b/shillelagh-processor/src/main/java/shillelagh/internal/ShillelaghProcessor.java index 5b42e90..795d481 100644 --- a/shillelagh-processor/src/main/java/shillelagh/internal/ShillelaghProcessor.java +++ b/shillelagh-processor/src/main/java/shillelagh/internal/ShillelaghProcessor.java @@ -140,12 +140,13 @@ public final class ShillelaghProcessor extends AbstractProcessor { Element element = tableObject.getOriginatingElement(); try { + // Write out the create statement. JavaFileManager.Location location = StandardLocation.SOURCE_OUTPUT; String path = getPackageName(element); String file = tableObject.getTableName() + ".sql"; FileObject resource = filer.createResource(location, path, file, element); Writer writer = resource.openWriter(); - writer.write(tableObject.getSchema()); + writer.write(tableObject.toString()); writer.flush(); writer.close(); } catch (IOException e) { diff --git a/shillelagh-processor/src/main/java/shillelagh/internal/TableObject.java b/shillelagh-processor/src/main/java/shillelagh/internal/TableObject.java index 00e57d7..2b514ac 100644 --- a/shillelagh-processor/src/main/java/shillelagh/internal/TableObject.java +++ b/shillelagh-processor/src/main/java/shillelagh/internal/TableObject.java @@ -49,23 +49,23 @@ class TableObject { - private static final String SERIALIZE_FUNCTION = "serialize"; - private static final String DESERIALIZE_FUNCTION = "deserialize"; + private static final String SERIALIZE_FUNCTION = "ShillelaghUtil.serialize"; + private static final String DESERIALIZE_FUNCTION = "ShillelaghUtil.deserialize"; private static final String GET_ID_FUNCTION = "getId"; private static final String SELECT_ALL_FUNCTION = "selectAll"; private static final String PARENT_INSERT_FUNCTION = "parentInsert"; private static final String INSERT_ONE_TO_ONE = "insertOneToOne"; /** Used as a template to create a new table */ - private static final String CREATE_TABLE_DEFAULT = "CREATE TABLE %s " - + "(%s INTEGER PRIMARY KEY AUTOINCREMENT, %s);"; + private static final String CREATE_TABLE_DEFAULT = + "CREATE TABLE %s " + "(%s INTEGER PRIMARY KEY AUTOINCREMENT, %s);"; /** * SQL statement to select the id of the last inserted row. Does not end with ; in order to be * used with SQLiteDatabase#rawQuery(String, String[]) */ - private static final String GET_ID_OF_LAST_INSERTED_ROW_SQL - = "SELECT ROWID FROM %s ORDER BY ROWID DESC LIMIT 1"; + private static final String GET_ID_OF_LAST_INSERTED_ROW_SQL = + "SELECT ROWID FROM %s ORDER BY ROWID DESC LIMIT 1"; private final Element element; private final String classPackage; @@ -113,7 +113,7 @@ String getTargetClass() { } /** Get table schema */ - String getSchema() { + private String getSchema() { StringBuilder sb = new StringBuilder(); Iterator iterator = columns.iterator(); while (iterator.hasNext()) { @@ -146,14 +146,14 @@ void brewJava(Writer writer) throws IOException { JavaWriter javaWriter = new JavaWriter(writer); javaWriter.setCompressingTypes(false); - javaWriter.emitSingleLineComment("Generated code from Shillelagh. Do not modify!") - .emitPackage(classPackage) - /* Knows nothing of android types */ - .emitImports("android.content.ContentValues", "android.database.Cursor", - "android.database.DatabaseUtils", "android.database.sqlite.SQLiteDatabase") - .emitImports(ByteArrayInputStream.class, ByteArrayOutputStream.class, IOException.class, - ObjectInputStream.class, ObjectOutputStream.class, LinkedList.class, Date.class, - List.class) + javaWriter.emitSingleLineComment("Generated code from Shillelagh. Do not modify!") // + .emitPackage(classPackage) // + /* Knows nothing of android types, must use strings. */ // + .emitImports("android.content.ContentValues", "android.database.Cursor", // + "android.database.DatabaseUtils", "android.database.sqlite.SQLiteDatabase") // + .emitImports(ShillelaghUtil.class, ByteArrayInputStream.class, ByteArrayOutputStream.class, + IOException.class, ObjectInputStream.class, ObjectOutputStream.class, LinkedList.class, + Date.class, List.class) // .beginType(className, "class", EnumSet.of(PUBLIC, FINAL)); if (this.isChildTable) { @@ -172,33 +172,28 @@ void brewJava(Writer writer) throws IOException { emitMapCursorToObject(javaWriter); emitSingleMap(javaWriter); emitSelectById(javaWriter); - emitByteArraySerialization(javaWriter); javaWriter.endType(); } /** Create a way to get an id for foreign keys */ private void emitGetId(JavaWriter javaWriter) throws IOException { logger.d("emitGetId"); - javaWriter.beginMethod( - "long", GET_ID_FUNCTION, EnumSet.of(PUBLIC, STATIC), getTargetClass(), "value") - .emitStatement("return value.%s", idColumnName) - .endMethod(); + javaWriter.beginMethod("long", GET_ID_FUNCTION, EnumSet.of(PUBLIC, STATIC), getTargetClass(), + "value").emitStatement("return value.%s", idColumnName).endMethod(); } /** Creates the function for creating the table */ private void emitCreateTable(JavaWriter javaWriter) throws IOException { logger.d("emitCreateTable"); - javaWriter.beginMethod( - "void", $$CREATE_TABLE_FUNCTION, EnumSet.of(PUBLIC, STATIC), "SQLiteDatabase", "db") - .emitStatement("db.execSQL(\"%s\")", getSchema()) - .endMethod(); + javaWriter.beginMethod("void", $$CREATE_TABLE_FUNCTION, EnumSet.of(PUBLIC, STATIC), + "SQLiteDatabase", "db").emitStatement("db.execSQL(\"%s\")", getSchema()).endMethod(); } /** Creates the function dropping the table */ private void emitDropTable(JavaWriter javaWriter) throws IOException { logger.d("emitDropTable"); - javaWriter.beginMethod( - "void", $$DROP_TABLE_FUNCTION, EnumSet.of(PUBLIC, STATIC), "SQLiteDatabase", "db") + javaWriter.beginMethod("void", $$DROP_TABLE_FUNCTION, EnumSet.of(PUBLIC, STATIC), + "SQLiteDatabase", "db") .emitStatement("db.execSQL(\"DROP TABLE IF EXISTS %s\")", getTableName()) .endMethod(); } @@ -217,13 +212,13 @@ private void emitInsert(JavaWriter javaWriter) throws IOException { javaWriter.emitStatement("values.put(\"%s\", %s(element.%s))", columnName, SERIALIZE_FUNCTION, columnName); } else if (column.isOneToOne()) { - javaWriter.emitStatement("%s%s.%s(element.%s, db)", column.getType(), - $$SUFFIX, INSERT_ONE_TO_ONE, column.getColumnName()) - .emitStatement("values.put(\"%s\", %s%s.%s(element.%s))", columnName, - column.getType(), $$SUFFIX, GET_ID_FUNCTION, columnName); + javaWriter.emitStatement("%s%s.%s(element.%s, db)", column.getType(), $$SUFFIX, + INSERT_ONE_TO_ONE, column.getColumnName()) + .emitStatement("values.put(\"%s\", %s%s.%s(element.%s))", columnName, column.getType(), + $$SUFFIX, GET_ID_FUNCTION, columnName); } else if (column.isDate()) { - javaWriter.emitStatement( - "values.put(\"%s\", element.%s.getTime())", columnName, columnName); + javaWriter.emitStatement("values.put(\"%s\", element.%s.getTime())", columnName, + columnName); } else if (column.isOneToMany()) { childColumns.add(column); } else if (!column.isOneToManyChild()) { @@ -237,8 +232,8 @@ private void emitInsert(JavaWriter javaWriter) throws IOException { + "\"SELECT ROWID FROM %s ORDER BY ROWID DESC LIMIT 1\", null)", tableName); } for (TableColumn childColumn : childColumns) { - javaWriter.emitStatement("%s%s.%s(id, element.%s, db)", childColumn.getType(), - $$SUFFIX, PARENT_INSERT_FUNCTION, childColumn.getColumnName()); + javaWriter.emitStatement("%s%s.%s(id, element.%s, db)", childColumn.getType(), $$SUFFIX, + PARENT_INSERT_FUNCTION, childColumn.getColumnName()); } javaWriter.endMethod(); @@ -305,8 +300,7 @@ private void emitDeleteWithObject(JavaWriter javaWriter) throws IOException { logger.d("emitDeleteWithObject"); javaWriter.beginMethod("void", $$DELETE_OBJECT_FUNCTION, EnumSet.of(PUBLIC, STATIC), getTargetClass(), "element", "SQLiteDatabase", "db") - .emitStatement( - "%s(element.%s, db)", $$DELETE_OBJECT_FUNCTION, idColumnName) + .emitStatement("%s(element.%s, db)", $$DELETE_OBJECT_FUNCTION, idColumnName) .endMethod(); } @@ -332,8 +326,8 @@ private void emitMapCursorToObject(JavaWriter javaWriter) throws IOException { private void emitSingleMap(JavaWriter javaWriter) throws IOException { String targetClass = getTargetClass(); - javaWriter.beginMethod(targetClass, $$MAP_SINGLE_FUNCTION, EnumSet.of(PUBLIC, STATIC), - "Cursor", "cursor", "SQLiteDatabase", "db") + javaWriter.beginMethod(targetClass, $$MAP_SINGLE_FUNCTION, EnumSet.of(PUBLIC, STATIC), "Cursor", + "cursor", "SQLiteDatabase", "db") .emitStatement("%s tableObject = new %s()", targetClass, getTargetClass()) .emitStatement("tableObject.%s = cursor.getLong(cursor.getColumnIndex(\"%s\"))", idColumnName, idColumnName); @@ -346,8 +340,8 @@ private void emitSingleMap(JavaWriter javaWriter) throws IOException { CursorFunctions.get(long.class.getName()), columnName); } else if (column.isOneToOne()) { javaWriter.emitStatement( - "tableObject.%s = %s%s.%s(cursor.%s(cursor.getColumnIndex(\"%s\")), db)", - columnName, column.getType(), $$SUFFIX, $$GET_OBJECT_BY_ID, + "tableObject.%s = %s%s.%s(cursor.%s(cursor.getColumnIndex(\"%s\")), db)", columnName, + column.getType(), $$SUFFIX, $$GET_OBJECT_BY_ID, CursorFunctions.get(Long.class.getName()), columnName); } else if (column.isBoolean()) { javaWriter.emitStatement("tableObject.%s = cursor.%s(cursor.getColumnIndex(\"%s\")) == 1", @@ -357,15 +351,14 @@ private void emitSingleMap(JavaWriter javaWriter) throws IOException { javaWriter.emitStatement("tableObject.%s = cursor.%s(cursor.getColumnIndex(\"%s\"))", columnName, CursorFunctions.get(column.getType()), columnName); } else { - javaWriter.emitStatement( - "tableObject.%s = %s(cursor.%s(cursor.getColumnIndex(\"%s\")));", columnName, - DESERIALIZE_FUNCTION, CursorFunctions.get(column.getType()), columnName); + javaWriter.emitStatement("tableObject.%s = %s(cursor.%s(cursor.getColumnIndex(\"%s\")));", + columnName, DESERIALIZE_FUNCTION, CursorFunctions.get(column.getType()), columnName); } } else if (column.isOneToMany()) { - javaWriter.emitStatement("Cursor childCursor = %s%s.%s(db)", column.getType(), - $$SUFFIX, SELECT_ALL_FUNCTION) - .emitStatement("tableObject.%s = %s%s.%s(childCursor, db)", - column.getColumnName(), column.getType(), $$SUFFIX, $$MAP_OBJECT_FUNCTION) + javaWriter.emitStatement("Cursor childCursor = %s%s.%s(db)", column.getType(), $$SUFFIX, + SELECT_ALL_FUNCTION) + .emitStatement("tableObject.%s = %s%s.%s(childCursor, db)", column.getColumnName(), + column.getType(), $$SUFFIX, $$MAP_OBJECT_FUNCTION) .emitStatement("childCursor.close()"); } else if (column.isOneToManyChild()) { // TODO Skip and have custom mapping? @@ -375,8 +368,7 @@ private void emitSingleMap(JavaWriter javaWriter) throws IOException { } } - javaWriter.emitStatement("return tableObject") - .endMethod(); + javaWriter.emitStatement("return tableObject").endMethod(); } /** Creates function for getting an object by value */ @@ -384,8 +376,8 @@ private void emitSelectById(JavaWriter javaWriter) throws IOException { logger.d("emitSelectById"); javaWriter.beginMethod(getTargetClass(), $$GET_OBJECT_BY_ID, EnumSet.of(PUBLIC, STATIC), "long", "id", "SQLiteDatabase", "db") - .emitStatement("Cursor cursor = db.rawQuery(\"SELECT * FROM %s WHERE %s = id\", null)" - , getTableName(), idColumnName) + .emitStatement("Cursor cursor = db.rawQuery(\"SELECT * FROM %s WHERE %s = id\", null)", + getTableName(), idColumnName) .emitStatement("%s value = %s(cursor, db).get(0)", getTargetClass(), $$MAP_OBJECT_FUNCTION) .emitStatement("cursor.close()") .emitStatement("return value") @@ -393,25 +385,23 @@ private void emitSelectById(JavaWriter javaWriter) throws IOException { } private void emitParentInsert(JavaWriter javaWriter) throws IOException { - javaWriter.beginMethod("void", PARENT_INSERT_FUNCTION, EnumSet.of(PUBLIC, STATIC), - "long", "parentId", String.format("List<%s>", getTargetClass()), "children", - "SQLiteDatabase", "db") + javaWriter.beginMethod("void", PARENT_INSERT_FUNCTION, EnumSet.of(PUBLIC, STATIC), "long", + "parentId", String.format("List<%s>", getTargetClass()), "children", "SQLiteDatabase", "db") .beginControlFlow("for(%s child : children)", getTargetClass()) .emitStatement("ContentValues values = new ContentValues()"); for (TableColumn column : columns) { String columnName = column.getColumnName(); if (column.getSqlType() == SqliteType.BLOB && !column.isByteArray()) { - javaWriter.emitStatement("values.put(\"%s\", %s(child.%s))", columnName, - SERIALIZE_FUNCTION, columnName); + javaWriter.emitStatement("values.put(\"%s\", %s(child.%s))", columnName, SERIALIZE_FUNCTION, + columnName); } else if (column.isOneToOne()) { javaWriter.emitStatement("values.put(\"%s\", %s%s.%s(child.%s))", columnName, column.getType(), $$SUFFIX, GET_ID_FUNCTION, columnName); } else if (column.isDate()) { - javaWriter.emitStatement( - "values.put(\"%s\", child.%s.getTime())", columnName, columnName); + javaWriter.emitStatement("values.put(\"%s\", child.%s.getTime())", columnName, columnName); } else if (column.getSqlType() == SqliteType.ONE_TO_MANY) { - javaWriter.emitStatement("%s.%s.%s(%s)", column.getType(), $$SUFFIX, - PARENT_INSERT_FUNCTION, columnName); + javaWriter.emitStatement("%s.%s.%s(%s)", column.getType(), $$SUFFIX, PARENT_INSERT_FUNCTION, + columnName); } else if (column.getSqlType() == SqliteType.ONE_TO_MANY_CHILD) { javaWriter.emitStatement("values.put(\"%s\", %s)", columnName, "parentId"); } else { @@ -445,35 +435,7 @@ private void emitOneToOneInsert(JavaWriter javaWriter) throws IOException { .endMethod(); } - /** Creates functions for serialization to and from byte arrays */ - private void emitByteArraySerialization(JavaWriter javaWriter) throws IOException { - logger.d("emitByteArraySerialization"); - javaWriter.beginMethod(" byte[]", SERIALIZE_FUNCTION, EnumSet.of(STATIC), "K", "object") - .beginControlFlow("try") - .emitStatement("ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()") - .emitStatement( - "ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream)") - .emitStatement("objectOutputStream.writeObject(object)") - .emitStatement("return byteArrayOutputStream.toByteArray()") - .nextControlFlow("catch (IOException e)") - .emitStatement("throw new RuntimeException(e)") - .endControlFlow() - .endMethod() - .beginMethod(" K", DESERIALIZE_FUNCTION, EnumSet.of(STATIC), "byte[]", "bytes") - .beginControlFlow("try") - .emitStatement( - "ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes)") - .emitStatement( - "ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream)") - .emitStatement("return (K) objectInputStream.readObject()") - .nextControlFlow("catch (IOException e)") - .emitStatement("throw new RuntimeException(e)") - .nextControlFlow("catch (ClassNotFoundException e)") - .emitStatement("throw new RuntimeException(e)") - .endControlFlow() - .endMethod(); - } - + /** Retruns the create statement for this table object */ @Override public String toString() { return getSchema(); } diff --git a/shillelagh/src/main/java/shillelagh/internal/ShillelaghUtil.java b/shillelagh/src/main/java/shillelagh/internal/ShillelaghUtil.java new file mode 100644 index 0000000..c3fcb02 --- /dev/null +++ b/shillelagh/src/main/java/shillelagh/internal/ShillelaghUtil.java @@ -0,0 +1,54 @@ +/* + * Copyright 2014 Andrew Reitz + * + * 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 shillelagh.internal; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; + +public final class ShillelaghUtil { + + public static byte[] serialize(K object) { + try { + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream); + objectOutputStream.writeObject(object); + return byteArrayOutputStream.toByteArray(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + public static K deserialize(byte[] bytes) { + try { + ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes); + ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream); + @SuppressWarnings("unchecked") final K k = (K) objectInputStream.readObject(); + return k; + } catch (IOException e) { + throw new RuntimeException(e); + } catch (ClassNotFoundException e) { + throw new RuntimeException(e); + } + } + + private ShillelaghUtil() { + /* No Instances */ + } +}