mirror of https://github.com/tasks/tasks
Partial-work commit of tag migration and improvements to the data model.
parent
8e743d343f
commit
67d8483183
@ -0,0 +1,178 @@
|
||||
package com.todoroo.astrid.tags;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.DatabaseUtils;
|
||||
|
||||
import com.thoughtworks.sql.Criterion;
|
||||
import com.thoughtworks.sql.Order;
|
||||
import com.thoughtworks.sql.Query;
|
||||
import com.todoroo.andlib.data.TodorooCursor;
|
||||
import com.todoroo.andlib.data.Property.CountProperty;
|
||||
import com.todoroo.andlib.service.Autowired;
|
||||
import com.todoroo.andlib.service.DependencyInjectionService;
|
||||
import com.todoroo.astrid.api.AstridApiConstants;
|
||||
import com.todoroo.astrid.api.AstridContentProvider.AstridTask;
|
||||
import com.todoroo.astrid.dao.Database;
|
||||
import com.todoroo.astrid.dao.MetadataDao;
|
||||
import com.todoroo.astrid.dao.MetadataDao.MetadataCriteria;
|
||||
import com.todoroo.astrid.model.Metadata;
|
||||
import com.todoroo.astrid.service.MetadataService;
|
||||
|
||||
/**
|
||||
* Provides operations for working with tags
|
||||
*
|
||||
* @author Tim Su <tim@todoroo.com>
|
||||
*
|
||||
*/
|
||||
@SuppressWarnings("nls")
|
||||
public class DataService {
|
||||
|
||||
/**
|
||||
* Metadata key for tag data
|
||||
*/
|
||||
public static final String KEY = "tags-tag";
|
||||
|
||||
@Autowired
|
||||
private Database database;
|
||||
|
||||
@Autowired
|
||||
private MetadataDao metadataDao;
|
||||
|
||||
@Autowired
|
||||
private MetadataService metadataService;
|
||||
|
||||
public DataService(@SuppressWarnings("unused") Context context) {
|
||||
DependencyInjectionService.getInstance().inject(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Property for retrieving count of aggregated rows
|
||||
*/
|
||||
private static final CountProperty COUNT = new CountProperty();
|
||||
|
||||
public static final Order GROUPED_TAGS_BY_ALPHA = Order.asc(Metadata.VALUE);
|
||||
public static final Order GROUPED_TAGS_BY_SIZE = Order.desc(COUNT);
|
||||
|
||||
/**
|
||||
* Helper class for returning a tag/task count pair
|
||||
*
|
||||
* @author Tim Su <tim@todoroo.com>
|
||||
*
|
||||
*/
|
||||
public class Tag {
|
||||
String tag;
|
||||
int count;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return tag;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all tags ordered by given clause
|
||||
*
|
||||
* @param taskId
|
||||
* @return empty array if no tags, otherwise array
|
||||
*/
|
||||
public Tag[] getGroupedTags(Order order) {
|
||||
TodorooCursor<Metadata> cursor = metadataService.fetchWithCount(
|
||||
COUNT, MetadataCriteria.withKey(KEY), order, true);
|
||||
try {
|
||||
Tag[] array = new Tag[cursor.getCount()];
|
||||
for (int i = 0; i < array.length; i++) {
|
||||
cursor.moveToNext();
|
||||
array[i] = new Tag();
|
||||
array[i].tag = cursor.get(Metadata.VALUE);
|
||||
array[i].count = cursor.get(COUNT);
|
||||
}
|
||||
return array;
|
||||
} finally {
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return tags on the given task
|
||||
*
|
||||
* @param taskId
|
||||
* @return empty array if no tags, otherwise array
|
||||
*/
|
||||
public TodorooCursor<Metadata> getTags(long taskId) {
|
||||
Query query = Query.select(Metadata.VALUE).where(Criterion.and(MetadataCriteria.withKey(KEY),
|
||||
MetadataCriteria.byTask(taskId)));
|
||||
return metadataDao.query(query);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return tags as a comma-separated list of strings
|
||||
*
|
||||
* @param taskId
|
||||
* @return empty string if no tags, otherwise string
|
||||
*/
|
||||
public String getTagsAsString(long taskId) {
|
||||
StringBuilder tagBuilder = new StringBuilder();
|
||||
String[] tags = getTags(taskId);
|
||||
for (int i = 0; i < tags.length; i++) {
|
||||
tagBuilder.append(tags[i]);
|
||||
if (i < tags.length - 1)
|
||||
tagBuilder.append(", ");
|
||||
}
|
||||
return tagBuilder.toString();
|
||||
}
|
||||
|
||||
private static final String query = String.format("INNER JOIN %s ON %s = "
|
||||
+ "%s WHERE %s = 0 AND %s = '%s' AND %s = ",
|
||||
AstridApiConstants.METADATA_TABLE,
|
||||
AstridTask.ID, Metadata.TASK,
|
||||
AstridTask.COMPLETION_DATE,
|
||||
Metadata.KEY, KEY,
|
||||
Metadata.VALUE);
|
||||
|
||||
/**
|
||||
* Return SQL selector query for getting tasks with a given tag
|
||||
*
|
||||
* @param tag
|
||||
* @return
|
||||
*/
|
||||
public String getQuery(String tag) {
|
||||
return query + String.format("%s", DatabaseUtils.sqlEscapeString(tag));
|
||||
}
|
||||
|
||||
private static final String newTaskSql = String.format(
|
||||
"INSERT INTO %s (%s, %s, %s) " + "VALUES ($ID,'%s',",
|
||||
AstridApiConstants.METADATA_TABLE,
|
||||
Metadata.TASK.name,
|
||||
Metadata.KEY.name,
|
||||
Metadata.VALUE.name,
|
||||
KEY);
|
||||
|
||||
/**
|
||||
* Return SQL new task creator query
|
||||
* @param tag
|
||||
*/
|
||||
public String getNewTaskSql(String tag) {
|
||||
return newTaskSql + String.format("%s)", DatabaseUtils.sqlEscapeString(tag));
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the given array of tags into the database
|
||||
* @param taskId
|
||||
* @param tags
|
||||
*/
|
||||
public void synchronizeTags(long taskId, ArrayList<String> tags) {
|
||||
metadataDao.deleteWhere(database, MetadataSql.byTask(taskId) + " AND " +
|
||||
MetadataSql.withKey(KEY));
|
||||
|
||||
Metadata metadata = new Metadata();
|
||||
metadata.setValue(Metadata.KEY, KEY);
|
||||
metadata.setValue(Metadata.TASK, taskId);
|
||||
for(String tag : tags) {
|
||||
metadata.setValue(Metadata.VALUE, tag.trim());
|
||||
metadataDao.save(database, metadata);
|
||||
metadata.clearValue(Metadata.ID);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright (c) 2009, Todoroo Inc
|
||||
* All Rights Reserved
|
||||
* http://www.todoroo.com
|
||||
*/
|
||||
package com.todoroo.astrid.tagsold;
|
||||
|
||||
|
||||
import android.content.ContentValues;
|
||||
|
||||
import com.todoroo.andlib.data.AbstractModel;
|
||||
import com.todoroo.andlib.data.Property;
|
||||
import com.todoroo.andlib.data.Table;
|
||||
import com.todoroo.andlib.data.TodorooCursor;
|
||||
import com.todoroo.andlib.data.Property.LongProperty;
|
||||
import com.todoroo.andlib.data.Property.StringProperty;
|
||||
|
||||
/**
|
||||
* Data Model which represents a task users need to accomplish.
|
||||
*
|
||||
* @author Tim Su <tim@todoroo.com>
|
||||
*
|
||||
*/
|
||||
@SuppressWarnings("nls")
|
||||
public class Tag extends AbstractModel {
|
||||
|
||||
// --- table
|
||||
|
||||
public static final Table TABLE = new Table("tags", Tag.class);
|
||||
|
||||
// --- properties
|
||||
|
||||
/** ID */
|
||||
public static final LongProperty ID = new LongProperty(
|
||||
TABLE, ID_PROPERTY_NAME);
|
||||
|
||||
/** Name of Task */
|
||||
public static final StringProperty NAME = new StringProperty(
|
||||
TABLE, "name");
|
||||
|
||||
/** List of all properties for this model */
|
||||
public static final Property<?>[] PROPERTIES = generateProperties(Tag.class);
|
||||
|
||||
// --- defaults
|
||||
|
||||
/** Default values container */
|
||||
private static final ContentValues defaultValues = new ContentValues();
|
||||
|
||||
static {
|
||||
defaultValues.put(NAME.name, "");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContentValues getDefaultValues() {
|
||||
return defaultValues;
|
||||
}
|
||||
|
||||
// --- data access boilerplate
|
||||
|
||||
public Tag() {
|
||||
super();
|
||||
}
|
||||
|
||||
public Tag(TodorooCursor<Tag> cursor, Property<?>[] properties) {
|
||||
this();
|
||||
readPropertiesFromCursor(cursor, properties);
|
||||
}
|
||||
|
||||
public void readFromCursor(TodorooCursor<Tag> cursor, Property<?>[] properties) {
|
||||
super.readPropertiesFromCursor(cursor, properties);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getId() {
|
||||
return getIdHelper(ID);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* ASTRID: Android's Simple Task Recording Dashboard
|
||||
*
|
||||
* Copyright (c) 2009 Tim Su
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
package com.todoroo.astrid.tagsold;
|
||||
|
||||
import android.database.SQLException;
|
||||
|
||||
import com.thoughtworks.sql.Join;
|
||||
import com.thoughtworks.sql.Query;
|
||||
import com.todoroo.andlib.data.GenericDao;
|
||||
import com.todoroo.andlib.data.Property;
|
||||
import com.todoroo.andlib.data.TodorooCursor;
|
||||
import com.todoroo.astrid.model.Task;
|
||||
|
||||
/**
|
||||
* Service layer for tags plugin
|
||||
*
|
||||
* @author Tim Su <tim@todoroo.com>
|
||||
*
|
||||
*/
|
||||
public class TagService {
|
||||
|
||||
private GenericDao<Tag> tagDao;
|
||||
private GenericDao<TagToTaskMapping> tagToTaskDao;
|
||||
|
||||
public TagService() {
|
||||
TagsDatabase tagDatabase = new TagsDatabase();
|
||||
tagDao = new GenericDao<Tag>(Tag.class, tagDatabase);
|
||||
tagToTaskDao = new GenericDao<TagToTaskMapping>(TagToTaskMapping.class,
|
||||
tagDatabase);
|
||||
}
|
||||
|
||||
// --- tag batch operations
|
||||
|
||||
/** Get a list of all tags */
|
||||
public TodorooCursor<Tag> getAllTags(Property<?>... properties) {
|
||||
return tagDao.query(Query.select(properties));
|
||||
}
|
||||
|
||||
/** Get a list of tag identifiers for the given task */
|
||||
public TodorooCursor<Tag> getTaskTags(Task task, Property<?>... properties) throws SQLException {
|
||||
Query query = Query.select(properties).join(Join.inner(TagToTaskMapping.TABLE,
|
||||
Tag.ID.eq(TagToTaskMapping.TAG))).where(TagToTaskMapping.TASK.eq(task.getId()));
|
||||
return tagDao.query(query);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright (c) 2009, Todoroo Inc
|
||||
* All Rights Reserved
|
||||
* http://www.todoroo.com
|
||||
*/
|
||||
package com.todoroo.astrid.tagsold;
|
||||
|
||||
|
||||
import android.content.ContentValues;
|
||||
|
||||
import com.todoroo.andlib.data.AbstractModel;
|
||||
import com.todoroo.andlib.data.Property;
|
||||
import com.todoroo.andlib.data.Table;
|
||||
import com.todoroo.andlib.data.TodorooCursor;
|
||||
import com.todoroo.andlib.data.Property.LongProperty;
|
||||
|
||||
/**
|
||||
* Data Model which represents a task users need to accomplish.
|
||||
*
|
||||
* @author Tim Su <tim@todoroo.com>
|
||||
*
|
||||
*/
|
||||
@SuppressWarnings("nls")
|
||||
public class TagToTaskMapping extends AbstractModel {
|
||||
|
||||
// --- table
|
||||
|
||||
public static final Table TABLE = new Table("tagTaskMap", TagToTaskMapping.class);
|
||||
|
||||
// --- properties
|
||||
|
||||
/** Tag */
|
||||
public static final LongProperty TAG = new LongProperty(
|
||||
TABLE, "tag");
|
||||
|
||||
/** Task */
|
||||
public static final LongProperty TASK = new LongProperty(
|
||||
TABLE, "task");
|
||||
|
||||
/** List of all properties for this model */
|
||||
public static final Property<?>[] PROPERTIES = generateProperties(TagToTaskMapping.class);
|
||||
|
||||
// --- defaults
|
||||
|
||||
/** Default values container */
|
||||
private static final ContentValues defaultValues = new ContentValues();
|
||||
|
||||
@Override
|
||||
public ContentValues getDefaultValues() {
|
||||
return defaultValues;
|
||||
}
|
||||
|
||||
// --- data access boilerplate
|
||||
|
||||
public TagToTaskMapping() {
|
||||
super();
|
||||
}
|
||||
|
||||
public TagToTaskMapping(TodorooCursor<TagToTaskMapping> cursor, Property<?>[] properties) {
|
||||
this();
|
||||
readPropertiesFromCursor(cursor, properties);
|
||||
}
|
||||
|
||||
public void readFromCursor(TodorooCursor<TagToTaskMapping> cursor, Property<?>[] properties) {
|
||||
super.readPropertiesFromCursor(cursor, properties);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getId() {
|
||||
return NO_ID;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright (c) 2009, Todoroo Inc
|
||||
* All Rights Reserved
|
||||
* http://www.todoroo.com
|
||||
*/
|
||||
package com.todoroo.astrid.tagsold;
|
||||
|
||||
import com.todoroo.andlib.data.AbstractDatabase;
|
||||
import com.todoroo.andlib.data.Table;
|
||||
|
||||
/**
|
||||
* Database wrapper
|
||||
*
|
||||
* @author Tim Su <tim@todoroo.com>
|
||||
*
|
||||
*/
|
||||
@SuppressWarnings("nls")
|
||||
public class TagsDatabase extends AbstractDatabase {
|
||||
|
||||
// --- constants
|
||||
|
||||
/**
|
||||
* Database version number. This variable must be updated when database
|
||||
* tables are updated, as it determines whether a database needs updating.
|
||||
*/
|
||||
public static final int VERSION = 1;
|
||||
|
||||
/**
|
||||
* Database name (must be unique)
|
||||
*/
|
||||
private static final String NAME = "tags";
|
||||
|
||||
/**
|
||||
* List of table/ If you're adding a new table, add it to this list and
|
||||
* also make sure that our SQLite helper does the right thing.
|
||||
*/
|
||||
public static final Table[] TABLES = new Table[] {
|
||||
Tag.TABLE,
|
||||
TagToTaskMapping.TABLE,
|
||||
};
|
||||
|
||||
// --- implementation
|
||||
|
||||
@Override
|
||||
protected String getName() {
|
||||
return NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getVersion() {
|
||||
return VERSION;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Table[] getTables() {
|
||||
return TABLES;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreateTables() {
|
||||
StringBuilder sql = new StringBuilder();
|
||||
sql.append("CREATE INDEX IF NOT EXISTS tm_tag ON ").
|
||||
append(TagToTaskMapping.TABLE).append('(').
|
||||
append(TagToTaskMapping.TAG.name).
|
||||
append(')');
|
||||
database.execSQL(sql.toString());
|
||||
|
||||
sql.setLength(0);
|
||||
sql.append("CREATE INDEX IF NOT EXISTS tm_task ON ").
|
||||
append(TagToTaskMapping.TABLE).append('(').
|
||||
append(TagToTaskMapping.TASK.name).
|
||||
append(')');
|
||||
database.execSQL(sql.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean onUpgrade(int oldVersion, int newVersion) {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue