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

Add parcelable interface option to generator. #268

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@
out/
build/
local.properties
/bin/
6 changes: 2 additions & 4 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
Release History
---------------
### V2.1.0 Minor feature and bugfix release (2015-11-12, both core and generator)
### V2.1.0 Minor feature release (2015-09-XX, both core and generator)
* Official Robolectric support: workaround for a broken system call in Robolectric triggered by Query.forCurrentThread
* QueryBuilder now allows to create DISTINCT queries to avoid duplicate entities returned
* CursorQuery (beta, API might change)
* Deadlock prevention when loading a list of entities while doing concurrent updates
* Fixed async queries
* Better Android Studio support
* Generator: Possibility to supply custom JavaDoc for entities and their properties
* Added performance tests for: ActiveAndroid, Realm, Parse
* Generator: Fixed codeBeforeGetter, added codeBeforeGetterAndSetter

### V2.0.0 Major feature release (2015-07-30, both core and generator)
Expand Down
4 changes: 2 additions & 2 deletions DaoCore/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ apply plugin: 'signing'

group = 'de.greenrobot'
archivesBaseName = 'greendao'
version = '2.1.0'
version = '2.1.0-SNAPSHOT'
sourceCompatibility = 1.6

def isSnapshot = version.endsWith('-SNAPSHOT')
Expand Down Expand Up @@ -45,7 +45,7 @@ javadoc {
failOnError = false
classpath += configurations.provided
title = " greenDAO ${version} API"
options.bottom = 'Available under the Apache License, Version 2.0 - <i>Copyright &#169; 2011-2015 <a href="http://greenrobot.de/">greenrobot.de</a>. All Rights Reserved.</i>'
options.bottom = 'Available under the Apache License, Version 2.0 - <i>Copyright &#169; 2011-2013 <a href="http://greenrobot.de/">greenrobot.de</a>. All Rights Reserved.</i>'
excludes = ['de/greenrobot/dao/internal','de/greenrobot/dao/Internal*']
}

Expand Down
142 changes: 57 additions & 85 deletions DaoCore/src/main/java/de/greenrobot/dao/AbstractDao.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,17 @@

package de.greenrobot.dao;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;

import android.database.CrossProcessCursor;
import android.database.Cursor;
import android.database.CursorWindow;
import android.database.DatabaseUtils;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteStatement;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

import de.greenrobot.dao.identityscope.IdentityScope;
import de.greenrobot.dao.identityscope.IdentityScopeLong;
import de.greenrobot.dao.internal.DaoConfig;
Expand All @@ -39,12 +37,15 @@

/**
* Base class for all DAOs: Implements entity operations like insert, load, delete, and query.
* <p>
*
* This class is thread-safe.
*
* @param <T> Entity type
* @param <K> Primary key (PK) type; use Void if entity does not have exactly one PK
* @author Markus
*
* @param <T>
* Entity type
* @param <K>
* Primary key (PK) type; use Void if entity does not have exactly one PK
*/
/*
* When operating on TX, statements, or identity scope the following locking order must be met to avoid deadlocks:
Expand Down Expand Up @@ -117,7 +118,8 @@ public String[] getNonPkColumns() {
/**
* Loads and entity for the given PK.
*
* @param key a PK value or null
* @param key
* a PK value or null
* @return The entity or null, if no entity matched the PK value
*/
public T load(K key) {
Expand All @@ -132,13 +134,13 @@ public T load(K key) {
}
}
String sql = statements.getSelectByKey();
String[] keyArray = new String[]{key.toString()};
String[] keyArray = new String[] { key.toString() };
Cursor cursor = db.rawQuery(sql, keyArray);
return loadUniqueAndCloseCursor(cursor);
}

public T loadByRowId(long rowId) {
String[] idArray = new String[]{Long.toString(rowId)};
String[] idArray = new String[] { Long.toString(rowId) };
Cursor cursor = db.rawQuery(statements.getSelectByRowId(), idArray);
return loadUniqueAndCloseCursor(cursor);
}
Expand Down Expand Up @@ -188,7 +190,8 @@ protected List<T> loadAllAndCloseCursor(Cursor cursor) {
/**
* Inserts the given entities in the database using a transaction.
*
* @param entities The entities to insert.
* @param entities
* The entities to insert.
*/
public void insertInTx(Iterable<T> entities) {
insertInTx(entities, isEntityUpdateable());
Expand All @@ -197,7 +200,8 @@ public void insertInTx(Iterable<T> entities) {
/**
* Inserts the given entities in the database using a transaction.
*
* @param entities The entities to insert.
* @param entities
* The entities to insert.
*/
public void insertInTx(T... entities) {
insertInTx(Arrays.asList(entities), isEntityUpdateable());
Expand All @@ -207,8 +211,10 @@ public void insertInTx(T... entities) {
* Inserts the given entities in the database using a transaction. The given entities will become tracked if the PK
* is set.
*
* @param entities The entities to insert.
* @param setPrimaryKey if true, the PKs of the given will be set after the insert; pass false to improve performance.
* @param entities
* The entities to insert.
* @param setPrimaryKey
* if true, the PKs of the given will be set after the insert; pass false to improve performance.
*/
public void insertInTx(Iterable<T> entities, boolean setPrimaryKey) {
SQLiteStatement stmt = statements.getInsertStatement();
Expand All @@ -219,8 +225,10 @@ public void insertInTx(Iterable<T> entities, boolean setPrimaryKey) {
* Inserts or replaces the given entities in the database using a transaction. The given entities will become
* tracked if the PK is set.
*
* @param entities The entities to insert.
* @param setPrimaryKey if true, the PKs of the given will be set after the insert; pass false to improve performance.
* @param entities
* The entities to insert.
* @param setPrimaryKey
* if true, the PKs of the given will be set after the insert; pass false to improve performance.
*/
public void insertOrReplaceInTx(Iterable<T> entities, boolean setPrimaryKey) {
SQLiteStatement stmt = statements.getInsertOrReplaceStatement();
Expand All @@ -230,7 +238,8 @@ public void insertOrReplaceInTx(Iterable<T> entities, boolean setPrimaryKey) {
/**
* Inserts or replaces the given entities in the database using a transaction.
*
* @param entities The entities to insert.
* @param entities
* The entities to insert.
*/
public void insertOrReplaceInTx(Iterable<T> entities) {
insertOrReplaceInTx(entities, isEntityUpdateable());
Expand All @@ -239,7 +248,8 @@ public void insertOrReplaceInTx(Iterable<T> entities) {
/**
* Inserts or replaces the given entities in the database using a transaction.
*
* @param entities The entities to insert.
* @param entities
* The entities to insert.
*/
public void insertOrReplaceInTx(T... entities) {
insertOrReplaceInTx(Arrays.asList(entities), isEntityUpdateable());
Expand Down Expand Up @@ -359,18 +369,12 @@ protected void updateKeyAfterInsertAndAttach(T entity, long rowId, boolean lock)
/** Reads all available rows from the given cursor and returns a list of entities. */
protected List<T> loadAllFromCursor(Cursor cursor) {
int count = cursor.getCount();
if (count == 0) {
return Collections.EMPTY_LIST;
}
List<T> list = new ArrayList<T>(count);
CursorWindow window = null;
boolean useFastCursor = false;
if (cursor instanceof CrossProcessCursor) {
window = ((CrossProcessCursor) cursor).getWindow();
if (window != null) { // E.g. Robolectric has no Window at this point
CursorWindow window = ((CrossProcessCursor) cursor).getWindow();
if (window != null) { // E.g. Roboelectric has no Window at this point
if (window.getNumRows() == count) {
cursor = new FastCursor(window);
useFastCursor = true;
} else {
DaoLog.d("Window vs. result size: " + window.getNumRows() + "/" + count);
}
Expand All @@ -382,15 +386,10 @@ protected List<T> loadAllFromCursor(Cursor cursor) {
identityScope.lock();
identityScope.reserveRoom(count);
}

try {
if (!useFastCursor && window != null && identityScope != null) {
loadAllUnlockOnWindowBounds(cursor, window, list);
} else {
do {
list.add(loadCurrent(cursor, 0, false));
} while (cursor.moveToNext());
}
do {
list.add(loadCurrent(cursor, 0, false));
} while (cursor.moveToNext());
} finally {
if (identityScope != null) {
identityScope.unlock();
Expand All @@ -400,42 +399,6 @@ protected List<T> loadAllFromCursor(Cursor cursor) {
return list;
}

private void loadAllUnlockOnWindowBounds(Cursor cursor, CursorWindow window, List<T> list) {
int windowEnd = window.getStartPosition() + window.getNumRows();
for (int row = 0; ; row++) {
list.add(loadCurrent(cursor, 0, false));
row++;
if (row >= windowEnd) {
window = moveToNextUnlocked(cursor);
if(window == null) {
break;
}
windowEnd = window.getStartPosition() + window.getNumRows();
} else {
if(!cursor.moveToNext()) {
break;
}
}
}
}

/**
* Unlock identityScope during cursor.moveToNext() when it is about to fill the window (needs a db connection):
* We should not hold the lock while trying to acquire a db connection to avoid deadlocks.
*/
private CursorWindow moveToNextUnlocked(Cursor cursor) {
identityScope.unlock();
try {
if(cursor.moveToNext()) {
return ((CrossProcessCursor) cursor).getWindow();
} else {
return null;
}
} finally {
identityScope.lock();
}
}

/** Internal use only. Considers identity scope. */
final protected T loadCurrent(Cursor cursor, int offset, boolean lock) {
if (identityScopeLong != null) {
Expand Down Expand Up @@ -617,7 +580,8 @@ private void deleteInTxInternal(Iterable<T> entities, Iterable<K> keys) {
/**
* Deletes the given entities in the database using a transaction.
*
* @param entities The entities to delete.
* @param entities
* The entities to delete.
*/
public void deleteInTx(Iterable<T> entities) {
deleteInTxInternal(entities, null);
Expand All @@ -626,7 +590,8 @@ public void deleteInTx(Iterable<T> entities) {
/**
* Deletes the given entities in the database using a transaction.
*
* @param entities The entities to delete.
* @param entities
* The entities to delete.
*/
public void deleteInTx(T... entities) {
deleteInTxInternal(Arrays.asList(entities), null);
Expand All @@ -635,7 +600,8 @@ public void deleteInTx(T... entities) {
/**
* Deletes all entities with the given keys in the database using a transaction.
*
* @param keys Keys of the entities to delete.
* @param keys
* Keys of the entities to delete.
*/
public void deleteByKeyInTx(Iterable<K> keys) {
deleteInTxInternal(null, keys);
Expand All @@ -644,7 +610,8 @@ public void deleteByKeyInTx(Iterable<K> keys) {
/**
* Deletes all entities with the given keys in the database using a transaction.
*
* @param keys Keys of the entities to delete.
* @param keys
* Keys of the entities to delete.
*/
public void deleteByKeyInTx(K... keys) {
deleteInTxInternal(null, Arrays.asList(keys));
Expand All @@ -655,7 +622,7 @@ public void refresh(T entity) {
assertSinglePk();
K key = getKeyVerified(entity);
String sql = statements.getSelectByKey();
String[] keyArray = new String[]{key.toString()};
String[] keyArray = new String[] { key.toString() };
Cursor cursor = db.rawQuery(sql, keyArray);
try {
boolean available = cursor.moveToFirst();
Expand Down Expand Up @@ -716,9 +683,11 @@ protected void updateInsideSynchronized(T entity, SQLiteStatement stmt, boolean
/**
* Attaches the entity to the identity scope. Calls attachEntity(T entity).
*
* @param key Needed only for identity scope, pass null if there's none.
* @param entity The entitiy to attach
*/
* @param key
* Needed only for identity scope, pass null if there's none.
* @param entity
* The entitiy to attach
* */
protected final void attachEntity(K key, T entity, boolean lock) {
attachEntity(entity);
if (identityScope != null && key != null) {
Expand All @@ -734,15 +703,17 @@ protected final void attachEntity(K key, T entity, boolean lock) {
* Sub classes with relations additionally set the DaoMaster here. Must be called before the entity is attached to
* the identity scope.
*
* @param entity The entitiy to attach
*/
* @param entity
* The entitiy to attach
* */
protected void attachEntity(T entity) {
}

/**
* Updates the given entities in the database using a transaction.
*
* @param entities The entities to insert.
* @param entities
* The entities to insert.
*/
public void updateInTx(Iterable<T> entities) {
SQLiteStatement stmt = statements.getUpdateStatement();
Expand Down Expand Up @@ -783,7 +754,8 @@ public void updateInTx(Iterable<T> entities) {
/**
* Updates the given entities in the database using a transaction.
*
* @param entities The entities to update.
* @param entities
* The entities to update.
*/
public void updateInTx(T... entities) {
updateInTx(Arrays.asList(entities));
Expand Down
6 changes: 5 additions & 1 deletion DaoCore/src/main/java/de/greenrobot/dao/Property.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,17 @@ public class Property {
public final String name;
public final boolean primaryKey;
public final String columnName;
public final String sqlType;
public final int version;

public Property(int ordinal, Class<?> type, String name, boolean primaryKey, String columnName) {
public Property(int ordinal, Class<?> type, String name, boolean primaryKey, String columnName, String sqlType, int version) {
this.ordinal = ordinal;
this.type = type;
this.name = name;
this.primaryKey = primaryKey;
this.columnName = columnName;
this.sqlType = sqlType;
this.version = version;
}

/** Creates an "equal ('=')" condition for this property. */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,12 +104,12 @@ public static String createSqlInsert(String insertInto, String tablename, String
}

/** Creates an select for given columns with a trailing space */
public static String createSqlSelect(String tablename, String tableAlias, String[] columns, boolean distinct) {
public static String createSqlSelect(String tablename, String tableAlias, String[] columns) {
if (tableAlias == null || tableAlias.length() < 0) {
throw new DaoException("Table alias required");
}

StringBuilder builder = new StringBuilder(distinct ? "SELECT DISTINCT " : "SELECT ");
StringBuilder builder = new StringBuilder("SELECT ");
SqlUtils.appendColumns(builder, tableAlias, columns).append(" FROM ");
builder.append('"').append(tablename).append('"').append(' ').append(tableAlias).append(' ');
return builder.toString();
Expand Down
Loading