Merge remote branch 'stingeraj/dev' into dev

pull/14/head
Tim Su 14 years ago
commit ea10f25814

@ -1,39 +1,39 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>astrid</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.wst.common.project.facet.core.builder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>com.android.ide.eclipse.adt.ApkBuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>com.android.ide.eclipse.adt.AndroidNature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.eclipse.wst.common.project.facet.core.nature</nature>
</natures>
</projectDescription>
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>astrid</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.wst.common.project.facet.core.builder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>com.android.ide.eclipse.adt.ApkBuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>com.android.ide.eclipse.adt.AndroidNature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.eclipse.wst.common.project.facet.core.nature</nature>
</natures>
</projectDescription>

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.timsu.astrid"
android:versionName="3.1.0" android:versionCode="146"
android:installLocation="internalOnly">
android:versionName="3.1.0" android:versionCode="146">
<!-- android:installLocation="internalOnly"> -->
<!-- widgets, alarms, and services will break if Astrid is installed on SD card -->
@ -53,7 +53,7 @@
<supports-screens />
<application android:icon="@drawable/icon"
android:label="@string/app_name">
android:label="@string/app_name" android:debuggable="true">
<!-- ====================================================== Activities = -->

@ -10,5 +10,5 @@
# Indicates whether an apk should be generated for each density.
split.density=false
# Project target.
target=android-8
target=Motorola, Inc.:MILESTONE:7
apk-configurations=

@ -0,0 +1,156 @@
package com.todoroo.astrid.producteev;
import java.util.ArrayList;
import android.app.Activity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.AdapterView.OnItemSelectedListener;
import com.timsu.astrid.R;
import com.todoroo.andlib.service.Autowired;
import com.todoroo.andlib.service.DependencyInjectionService;
import com.todoroo.andlib.service.ExceptionService;
import com.todoroo.astrid.activity.TaskEditActivity.TaskEditControlSet;
import com.todoroo.astrid.model.Metadata;
import com.todoroo.astrid.model.StoreObject;
import com.todoroo.astrid.model.Task;
import com.todoroo.astrid.producteev.sync.ProducteevDashboard;
import com.todoroo.astrid.producteev.sync.ProducteevDataService;
import com.todoroo.astrid.producteev.sync.ProducteevTask;
import com.todoroo.astrid.producteev.sync.ProducteevUser;
/**
* Control Set for managing task/dashboard assignments in Producteev
*
* @author Arne Jans <arne.jans@gmail.com>
*
*/
public class ProducteevControlSet implements TaskEditControlSet {
// --- instance variables
@Autowired
private ExceptionService exceptionService;
private final Activity activity;
private Task myTask;
private final Spinner responsibleSelector;
private final Spinner dashboardSelector;
private ArrayList<ProducteevUser> users = null;
private ArrayList<ProducteevDashboard> dashboards = null;
public ProducteevControlSet(final Activity activity, ViewGroup parent) {
DependencyInjectionService.getInstance().inject(this);
this.activity = activity;
LayoutInflater.from(activity).inflate(R.layout.producteev_control, parent, true);
this.responsibleSelector = (Spinner) activity.findViewById(R.id.producteev_TEA_task_assign);
this.responsibleSelector.setOnItemSelectedListener(new OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view,
int position, long id) {
// TODO tim, please set a flag here somewhere, so that producteevinvoker knows
// it has to invoke tasks/set_responsible, or otherwise do it your way...
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
// TODO Auto-generated method stub
}
});
this.dashboardSelector = (Spinner) activity.findViewById(R.id.producteev_TEA_dashboard_assign);
this.dashboardSelector.setOnItemSelectedListener(new OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view,
int position, long id) {
// TODO tim, please set a flag here somewhere, so that producteevinvoker knows
// it has to invoke tasks/set_dashboard, or otherwise do it your way...
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
// TODO Auto-generated method stub
}
});
}
@Override
public void readFromTask(Task task) {
this.myTask = task;
Metadata metadata = ProducteevDataService.getInstance().getTaskMetadata(myTask.getId());
if (metadata != null) {
// Fill the dashboard-spinner and set the current dashboard
long dashboardId = metadata.getValue(ProducteevTask.DASHBOARD_ID);
StoreObject[] dashboardsData = ProducteevDataService.getInstance().getDashboards();
dashboards = new ArrayList(dashboardsData.length);
ProducteevDashboard ownerDashboard = null;
int dashboardSpinnerIndex = 0;
//dashboard to not sync as first spinner-entry
dashboards.add(new ProducteevDashboard(ProducteevUtilities.DASHBOARD_NO_SYNC, activity.getString(R.string.producteev_no_dashboard),null));
for (int i=1;i<dashboardsData.length+1;i++) {
ProducteevDashboard dashboard = new ProducteevDashboard(dashboardsData[i-1]);
dashboards.add(dashboard);
if(dashboard.getId() == dashboardId) {
ownerDashboard = dashboard;
dashboardSpinnerIndex = i;
}
}
ArrayAdapter<String> dashAdapter = new ArrayAdapter(activity,
android.R.layout.simple_spinner_item, dashboards);
dashAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
dashboardSelector.setAdapter(dashAdapter);
dashboardSelector.setSelection(dashboardSpinnerIndex);
if (ownerDashboard == null || ownerDashboard.getId() == ProducteevUtilities.DASHBOARD_NO_SYNC) {
responsibleSelector.setEnabled(false);
TextView emptyView = new TextView(activity);
emptyView.setText(activity.getText(R.string.producteev_no_dashboard));
responsibleSelector.setEmptyView(emptyView);
return;
}
// Fill the responsible-spinner and set the current responsible
users = ownerDashboard.getUsers();
long responsibleId = metadata.getValue(ProducteevTask.RESPONSIBLE_ID);
int userSpinnerIndex = 0;
for (ProducteevUser user : users) {
if (user.getId() == responsibleId) {
break;
}
userSpinnerIndex++;
}
ArrayAdapter<String> usersAdapter = new ArrayAdapter(activity,
android.R.layout.simple_spinner_item, users);
responsibleSelector.setAdapter(usersAdapter);
responsibleSelector.setSelection(userSpinnerIndex);
}
}
@SuppressWarnings("nls")
@Override
public void writeToModel(Task task) {
Metadata metadata = ProducteevDataService.getInstance().getTaskMetadata(task.getId());
if (metadata != null) {
ProducteevDashboard dashboard = (ProducteevDashboard) dashboardSelector.getSelectedItem();
metadata.setValue(ProducteevTask.DASHBOARD_ID, dashboard.getId());
ProducteevUser responsibleUser = (ProducteevUser) responsibleSelector.getSelectedItem();
metadata.setValue(ProducteevTask.RESPONSIBLE_ID, responsibleUser.getId());
}
}
}

@ -299,6 +299,35 @@ public class ProducteevInvoker {
"id_label", idLabel);
}
/**
* change responsible of a task
*
* @param idTask
* @param idResponsible
*
* @return array: tasks/view
*/
public JSONObject tasksSetResponsible(long idTask, long idResponsible) throws ApiServiceException, IOException {
return callAuthenticated("tasks/set_responsible.json",
"token", token,
"id_task", idTask,
"id_responsible", idResponsible);
}
/**
* change responsible of a task
*
* @param idTask
* @param idResponsible
*
* @return array: tasks/view
*/
public JSONObject tasksUnsetResponsible(long idTask) throws ApiServiceException, IOException {
return callAuthenticated("tasks/unset_responsible.json",
"token", token,
"id_task", idTask);
}
/**
* create a note attached to a task
*
@ -361,6 +390,19 @@ public class ProducteevInvoker {
"id_colleague", idColleague);
}
/**
* return the list of users who can access a specific dashboard
*
* @param idDashboard
* @param dashboard array-information about the dashboard, if this ...
*/
public JSONArray dashboardsAccess(long idDashboard, String dashboard) throws ApiServiceException, IOException {
return getResponse(callAuthenticated("dashboards/access",
"token", token,
"id_dashboard", idDashboard,
"dashboard", dashboard),"dashboard");
}
// --- invocation
private final ProducteevRestClient restClient = new ProducteevRestClient();

@ -1,5 +1,8 @@
package com.todoroo.astrid.producteev.sync;
import java.util.ArrayList;
import java.util.StringTokenizer;
import com.todoroo.andlib.data.Property.LongProperty;
import com.todoroo.andlib.data.Property.StringProperty;
import com.todoroo.astrid.model.StoreObject;
@ -27,4 +30,75 @@ public class ProducteevDashboard {
public static final StringProperty USERS = new StringProperty(StoreObject.TABLE,
StoreObject.VALUE2.name);
// data class-part
private final long id;
private final String name;
private ArrayList<ProducteevUser> users = null;
public ProducteevDashboard (StoreObject dashboardData) {
this(dashboardData.getValue(REMOTE_ID),dashboardData.getValue(NAME),dashboardData.getValue(USERS));
}
/**
* Constructor for a dashboard.
*
* @param id id of the remote dashboard
* @param name name of the remote dashboard
* @param usercsv csv-userstring as returned by a StoreObject-dashboard with property ProducteevDashboard.USERS
*/
public ProducteevDashboard(long id, String name, String usercsv) {
this.id = id;
this.name = name;
if (usercsv == null)
return;
StringTokenizer tokenizer = new StringTokenizer(usercsv, ";");
int usercount = tokenizer.countTokens();
while (tokenizer.hasMoreTokens()) {
String userdata = tokenizer.nextToken();
int delim_index = userdata.indexOf(",");
String userid = userdata.substring(0, delim_index);
String username = userdata.substring(delim_index+1);
int name_gap = username.indexOf(" ");
String firstname = (name_gap == -1 ? username : username.substring(0,name_gap));
String lastname = (name_gap == -1 ? null : username.substring(name_gap+1));
if (users == null) {
users = new ArrayList<ProducteevUser>(usercount);
}
users.add(new ProducteevUser(Long.parseLong(userid),null,firstname,lastname));
}
}
/**
* @return the id
*/
public long getId() {
return id;
}
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* return the name of this dashboard
*/
@Override
public String toString() {
return name;
}
/**
* @return the users
*/
public ArrayList<ProducteevUser> getUsers() {
return users;
}
}

@ -209,6 +209,8 @@ public final class ProducteevDataService {
private StoreObject[] dashboards = null;
private ArrayList colleagues;
/**
* Reads dashboards
*/
@ -284,4 +286,4 @@ public final class ProducteevDataService {
// clear dashboard cache
dashboards = null;
}
}
}

@ -644,6 +644,4 @@ public class ProducteevSyncProvider extends SyncProvider<ProducteevTaskContainer
((_-83)%27+97):_);return TextUtils.htmlEncode(____==31?___:
stripslashes(____+1,__.substring(1),___+((char)_)));
}
}

@ -0,0 +1,84 @@
package com.todoroo.astrid.producteev.sync;
import org.json.JSONException;
import org.json.JSONObject;
/**
*
* @author Arne Jans <arne.jans@gmail.com>
*/
@SuppressWarnings("nls")
public class ProducteevUser {
private final long id;
private final String email;
private final String firstname;
private final String lastname;
public ProducteevUser(long id, String email, String firstname, String lastname) {
this.id = id;
this.email = email;
this.firstname = firstname;
this.lastname = lastname;
}
public ProducteevUser(JSONObject elt) throws JSONException {
this.id = elt.getLong("id");
this.email = elt.getString("email");
this.firstname = elt.getString("firstname");
this.lastname = elt.getString("lastname");
}
/**
* @return the email
*/
public String getEmail() {
return email;
}
/**
* @return the firstname
*/
public String getFirstname() {
return firstname;
}
/**
* @return the lastname
*/
public String getLastname() {
return lastname;
}
/**
* @return the id
*/
public long getId() {
return id;
}
@Override
public String toString() {
String displayString = "";
boolean hasFirstname = false;
boolean hasLastname = false;
if (firstname != null && firstname.length() > 0) {
displayString += firstname;
hasFirstname = true;
}
if (lastname != null && lastname.length() > 0)
hasLastname = true;
if (hasFirstname && hasLastname)
displayString += " ";
if (hasLastname)
displayString += lastname;
if (!hasFirstname && !hasLastname && email != null && email.length() > 0)
displayString += email;
return displayString;
}
}

@ -0,0 +1,43 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- See the file "LICENSE" for the full license governing this code. -->
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<!-- producteev task assignment controlset -->
<LinearLayout
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/producteev_TEA_task_assign_label"
style="@style/TextAppearance.GEN_EditLabel" />
<Spinner
android:id="@+id/producteev_TEA_task_assign"
android:prompt="@string/producteev_TEA_task_assign_label"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/producteev_TEA_dashboard_assign_label"
style="@style/TextAppearance.GEN_EditLabel" />
<Spinner
android:id="@+id/producteev_TEA_dashboard_assign"
android:prompt="@string/producteev_TEA_dashboard_assign_label"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
</LinearLayout>
<View
android:layout_width="fill_parent"
android:layout_height="1dip"
android:padding="5dip"
android:background="@android:drawable/divider_horizontal_dark" />
</merge>

@ -100,5 +100,4 @@
android:linksClickable="true"
android:text="@string/producteev_PLA_terms" />
</LinearLayout>

@ -86,5 +86,18 @@
<!-- Prod Login password not specified-->
<string name="producteev_MLA_password_empty">Password was not specified!</string>
</resources>
<!-- ================================================ labels for layout-elements == -->
<!-- label for task-assignment spinner on taskeditactivity -->
<string name="producteev_TEA_task_assign_label">Assign this task to this person:</string>
<!-- Spinner-item for unassigned tasks on taskeditactivity -->
<string name="producteev_TEA_task_unassigned">&lt;Unassigned&gt;</string>
<!-- label for dashboard-assignment spinner on taskeditactivity -->
<string name="producteev_TEA_dashboard_assign_label">Assign this task to this workspace:</string>
<!-- Spinner-item for default dashboard on taskeditactivity -->
<string name="producteev_TEA_dashboard_default">&lt;Default&gt;</string>
</resources>

@ -27,14 +27,14 @@ import java.util.List;
import android.app.AlertDialog;
import android.app.DatePickerDialog;
import android.app.DatePickerDialog.OnDateSetListener;
import android.app.TabActivity;
import android.app.DatePickerDialog.OnDateSetListener;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnCancelListener;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.DialogInterface.OnCancelListener;
import android.content.res.Resources;
import android.os.Bundle;
import android.text.format.DateUtils;
@ -44,7 +44,6 @@ import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup.LayoutParams;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.CheckBox;
@ -59,6 +58,7 @@ import android.widget.TabHost;
import android.widget.TimePicker;
import android.widget.Toast;
import android.widget.ToggleButton;
import android.widget.AdapterView.OnItemSelectedListener;
import com.flurry.android.FlurryAgent;
import com.timsu.astrid.R;
@ -72,7 +72,9 @@ import com.todoroo.astrid.alarms.AlarmControlSet;
import com.todoroo.astrid.api.AstridApiConstants;
import com.todoroo.astrid.dao.Database;
import com.todoroo.astrid.gcal.GCalControlSet;
import com.todoroo.astrid.model.AddOn;
import com.todoroo.astrid.model.Task;
import com.todoroo.astrid.producteev.ProducteevControlSet;
import com.todoroo.astrid.producteev.ProducteevUtilities;
import com.todoroo.astrid.repeats.RepeatControlSet;
import com.todoroo.astrid.service.AddOnService;
@ -217,6 +219,10 @@ public final class TaskEditActivity extends TabActivity {
controls.add(new RepeatControlSet(this, extrasAddons));
LinearLayout addonsAddons = (LinearLayout) findViewById(R.id.tab_addons_addons);
AddOn producteevAddon = addOnService.getAddOn(AddOnService.PRODUCTEEV_PACKAGE, "Producteev");
if (addOnService.isInstalled(producteevAddon) && ProducteevUtilities.INSTANCE.isLoggedIn()) {
controls.add(new ProducteevControlSet(this, addonsAddons));
}
if(addOnService.hasPowerPack()) {
controls.add(new GCalControlSet(this, addonsAddons));
controls.add(new TimerControlSet(this, addonsAddons));

@ -42,6 +42,9 @@ public class AddOnService {
/** Astrid Locale package */
public static final String LOCALE_PACKAGE = "com.todoroo.astrid.locale";
/** Astrid Producteev package */
public static final String PRODUCTEEV_PACKAGE = "com.todoroo.astrid.producteev";
/** Astrid Power Pack label */
public static final String POWER_PACK_LABEL = "Astrid Power Pack";
@ -152,6 +155,9 @@ public class AddOnService {
* @return
*/
public boolean isInstalled(AddOn addOn) {
// it isnt installed if it is null...
if (addOn == null)
return false;
return isInstalled(addOn.getPackageName(), addOn.isInternal());
}
@ -165,6 +171,8 @@ public class AddOnService {
return true;
if(LOCALE_PACKAGE.equals(packageName))
return true;
if(PRODUCTEEV_PACKAGE.equals(packageName))
return true;
Context context = ContextManager.getContext();
PackageInfo packageInfo;
@ -183,6 +191,27 @@ public class AddOnService {
return "30820265308201cea00302010202044954bd9c300d06092a864886f70d01010505003076310b3009060355040613025553310b3009060355040813024341311230100603550407130950616c6f20416c746f31183016060355040a130f6173747269642e6c7632352e636f6d311b3019060355040b131241737472696420446576656c6f706d656e74310f300d0603550403130654696d2053753020170d3038313232363131313835325a180f32303633303932393131313835325a3076310b3009060355040613025553310b3009060355040813024341311230100603550407130950616c6f20416c746f31183016060355040a130f6173747269642e6c7632352e636f6d311b3019060355040b131241737472696420446576656c6f706d656e74310f300d0603550403130654696d20537530819f300d06092a864886f70d010101050003818d00308189028181008b8f39e02a50e5f50723bb71208e99bd72dd3cb6266054809cce0dc33a38ebf79c2a1ab74264cc6c88d44a5092e34f45fc28c53188ebe5b7511f0e14862598a82e1a84b0c99e62b0603737c09501b92f723d9e561a0eedbc16ab494e93a513d170135e0e55af6bb40a9af1186df4cfe53ec3a6144336f9f8a338341656c5a3bd0203010001300d06092a864886f70d01010505000381810016352860629e5e17d2d747943170ddb8c01f014932cb4462f52295c2f764970e93fa461c73b44a678ecf8ab8480702fb746221a98ade8ab7562cae151be78973dfa47144d70b8d0b73220dd741755f62cc9230264f570ec21a4ab1f11b0528d799d3662d06354b56d0d7d28d05c260876a98151fb4e89b6ce2a5010c52b3e365".equals(packageInfo.signatures[0].toCharsString());
}
/**
* Get one AddOn-descriptor by packageName and title.
*
* @param packageName could be Constants.PACKAGE or one of AddOnService-constants
* @param title the descriptive title, as in "Producteev" or "Astrid Power Pack"
* @return the addon-descriptor, if it is available (registered here in getAddOns), otherwise null
*/
public AddOn getAddOn(String packageName, String title) {
if (title == null || packageName == null)
return null;
AddOn addon = null;
AddOn[] addons = getAddOns();
for (int i = 0; i < addons.length ; i++) {
if (packageName.equals(addons[i].getPackageName()) && title.equals(addons[i].getTitle())) {
addon = addons[i];
}
}
return addon;
}
/**
* Get a list of add-ons
*
@ -210,7 +239,7 @@ public class AddOnService {
list[3] = new AddOn(true, true, "Producteev", null,
"Synchronize with Producteev service. Also changes Astrid's importance levels to stars.",
Constants.PACKAGE, "http://www.producteev.com",
PRODUCTEEV_PACKAGE, "http://www.producteev.com",
((BitmapDrawable)r.getDrawable(R.drawable.icon_producteev)).getBitmap());
return list;

@ -1,25 +1,25 @@
package com.todoroo.andlib;
@SuppressWarnings("nls")
public final class Constants {
static final String SELECT = "SELECT";
static final String SPACE = " ";
static final String AS = "AS";
static final String COMMA = ",";
static final String FROM = "FROM";
static final String ON = "ON";
static final String JOIN = "JOIN";
static final String ALL = "*";
static final String LEFT_PARENTHESIS = "(";
static final String RIGHT_PARENTHESIS = ")";
static final String AND = "AND";
static final String BETWEEN = "BETWEEN";
static final String LIKE = "LIKE";
static final String OR = "OR";
static final String ORDER_BY = "ORDER BY";
static final String GROUP_BY = "GROUP BY";
static final String WHERE = "WHERE";
public static final String EXISTS = "EXISTS";
public static final String NOT = "NOT";
public static final String LIMIT = "LIMIT";
}
package com.todoroo.andlib;
@SuppressWarnings("nls")
public final class Constants {
static final String SELECT = "SELECT";
static final String SPACE = " ";
static final String AS = "AS";
static final String COMMA = ",";
static final String FROM = "FROM";
static final String ON = "ON";
static final String JOIN = "JOIN";
static final String ALL = "*";
static final String LEFT_PARENTHESIS = "(";
static final String RIGHT_PARENTHESIS = ")";
static final String AND = "AND";
static final String BETWEEN = "BETWEEN";
static final String LIKE = "LIKE";
static final String OR = "OR";
static final String ORDER_BY = "ORDER BY";
static final String GROUP_BY = "GROUP BY";
static final String WHERE = "WHERE";
public static final String EXISTS = "EXISTS";
public static final String NOT = "NOT";
public static final String LIMIT = "LIMIT";
}

@ -1,89 +1,89 @@
package com.todoroo.andlib;
import static com.todoroo.andlib.Constants.AND;
import static com.todoroo.andlib.Constants.EXISTS;
import static com.todoroo.andlib.Constants.LEFT_PARENTHESIS;
import static com.todoroo.andlib.Constants.NOT;
import static com.todoroo.andlib.Constants.OR;
import static com.todoroo.andlib.Constants.RIGHT_PARENTHESIS;
import static com.todoroo.andlib.Constants.SPACE;
public abstract class Criterion {
protected final Operator operator;
Criterion(Operator operator) {
this.operator = operator;
}
public static Criterion all = new Criterion(Operator.exists) {
@Override
protected void populate(StringBuilder sb) {
sb.append(1);
}
};
public static Criterion none = new Criterion(Operator.exists) {
@Override
protected void populate(StringBuilder sb) {
sb.append(0);
}
};
public static Criterion and(final Criterion criterion, final Criterion... criterions) {
return new Criterion(Operator.and) {
@Override
protected void populate(StringBuilder sb) {
sb.append(criterion);
for (Criterion c : criterions) {
sb.append(SPACE).append(AND).append(SPACE).append(c);
}
}
};
}
public static Criterion or(final Criterion criterion, final Criterion... criterions) {
return new Criterion(Operator.or) {
@Override
protected void populate(StringBuilder sb) {
sb.append(criterion);
for (Criterion c : criterions) {
sb.append(SPACE).append(OR).append(SPACE).append(c.toString());
}
}
};
}
public static Criterion exists(final Query query) {
return new Criterion(Operator.exists) {
@Override
protected void populate(StringBuilder sb) {
sb.append(EXISTS).append(SPACE).append(LEFT_PARENTHESIS).append(query).append(RIGHT_PARENTHESIS);
}
};
}
public static Criterion not(final Criterion criterion) {
return new Criterion(Operator.not) {
@Override
protected void populate(StringBuilder sb) {
sb.append(NOT).append(SPACE);
criterion.populate(sb);
}
};
}
protected abstract void populate(StringBuilder sb);
@Override
public String toString() {
StringBuilder builder = new StringBuilder(LEFT_PARENTHESIS);
populate(builder);
builder.append(RIGHT_PARENTHESIS);
return builder.toString();
}
}
package com.todoroo.andlib;
import static com.todoroo.andlib.Constants.AND;
import static com.todoroo.andlib.Constants.EXISTS;
import static com.todoroo.andlib.Constants.LEFT_PARENTHESIS;
import static com.todoroo.andlib.Constants.NOT;
import static com.todoroo.andlib.Constants.OR;
import static com.todoroo.andlib.Constants.RIGHT_PARENTHESIS;
import static com.todoroo.andlib.Constants.SPACE;
public abstract class Criterion {
protected final Operator operator;
Criterion(Operator operator) {
this.operator = operator;
}
public static Criterion all = new Criterion(Operator.exists) {
@Override
protected void populate(StringBuilder sb) {
sb.append(1);
}
};
public static Criterion none = new Criterion(Operator.exists) {
@Override
protected void populate(StringBuilder sb) {
sb.append(0);
}
};
public static Criterion and(final Criterion criterion, final Criterion... criterions) {
return new Criterion(Operator.and) {
@Override
protected void populate(StringBuilder sb) {
sb.append(criterion);
for (Criterion c : criterions) {
sb.append(SPACE).append(AND).append(SPACE).append(c);
}
}
};
}
public static Criterion or(final Criterion criterion, final Criterion... criterions) {
return new Criterion(Operator.or) {
@Override
protected void populate(StringBuilder sb) {
sb.append(criterion);
for (Criterion c : criterions) {
sb.append(SPACE).append(OR).append(SPACE).append(c.toString());
}
}
};
}
public static Criterion exists(final Query query) {
return new Criterion(Operator.exists) {
@Override
protected void populate(StringBuilder sb) {
sb.append(EXISTS).append(SPACE).append(LEFT_PARENTHESIS).append(query).append(RIGHT_PARENTHESIS);
}
};
}
public static Criterion not(final Criterion criterion) {
return new Criterion(Operator.not) {
@Override
protected void populate(StringBuilder sb) {
sb.append(NOT).append(SPACE);
criterion.populate(sb);
}
};
}
protected abstract void populate(StringBuilder sb);
@Override
public String toString() {
StringBuilder builder = new StringBuilder(LEFT_PARENTHESIS);
populate(builder);
builder.append(RIGHT_PARENTHESIS);
return builder.toString();
}
}

@ -1,68 +1,68 @@
package com.todoroo.andlib;
import static com.todoroo.andlib.Constants.AS;
import static com.todoroo.andlib.Constants.SPACE;
public abstract class DBObject<T extends DBObject<?>> implements Cloneable {
protected String alias;
protected final String expression;
protected DBObject(String expression){
this.expression = expression;
}
@SuppressWarnings("unchecked")
public T as(String newAlias) {
try {
T clone = (T) clone();
clone.alias = newAlias;
return clone;
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
}
public boolean hasAlias() {
return alias != null;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
DBObject<?> dbObject = (DBObject<?>) o;
if (alias != null ? !alias.equals(dbObject.alias) : dbObject.alias != null) return false;
if (expression != null ? !expression.equals(dbObject.expression) : dbObject.expression != null) return false;
return true;
}
@Override
public int hashCode() {
int result = alias != null ? alias.hashCode() : 0;
result = 31 * result + (expression != null ? expression.hashCode() : 0);
return result;
}
@Override
public final String toString() {
if (hasAlias()) {
return alias;
}
return expression;
}
public final String toStringInSelect() {
StringBuilder sb = new StringBuilder(expression);
if (hasAlias()) {
sb.append(SPACE).append(AS).append(SPACE).append(alias);
} else {
int pos = expression.indexOf('.');
if(pos > 0)
sb.append(SPACE).append(AS).append(SPACE).append(expression.substring(pos + 1));
}
return sb.toString();
}
}
package com.todoroo.andlib;
import static com.todoroo.andlib.Constants.AS;
import static com.todoroo.andlib.Constants.SPACE;
public abstract class DBObject<T extends DBObject<?>> implements Cloneable {
protected String alias;
protected final String expression;
protected DBObject(String expression){
this.expression = expression;
}
@SuppressWarnings("unchecked")
public T as(String newAlias) {
try {
T clone = (T) clone();
clone.alias = newAlias;
return clone;
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
}
public boolean hasAlias() {
return alias != null;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
DBObject<?> dbObject = (DBObject<?>) o;
if (alias != null ? !alias.equals(dbObject.alias) : dbObject.alias != null) return false;
if (expression != null ? !expression.equals(dbObject.expression) : dbObject.expression != null) return false;
return true;
}
@Override
public int hashCode() {
int result = alias != null ? alias.hashCode() : 0;
result = 31 * result + (expression != null ? expression.hashCode() : 0);
return result;
}
@Override
public final String toString() {
if (hasAlias()) {
return alias;
}
return expression;
}
public final String toStringInSelect() {
StringBuilder sb = new StringBuilder(expression);
if (hasAlias()) {
sb.append(SPACE).append(AS).append(SPACE).append(alias);
} else {
int pos = expression.indexOf('.');
if(pos > 0)
sb.append(SPACE).append(AS).append(SPACE).append(expression.substring(pos + 1));
}
return sb.toString();
}
}

@ -1,7 +1,7 @@
package com.todoroo.andlib;
public class EqCriterion extends UnaryCriterion {
EqCriterion(Field field, Object value) {
super(field, Operator.eq, value);
}
}
package com.todoroo.andlib;
public class EqCriterion extends UnaryCriterion {
EqCriterion(Field field, Object value) {
super(field, Operator.eq, value);
}
}

@ -1,90 +1,90 @@
package com.todoroo.andlib;
import static com.todoroo.andlib.Constants.AND;
import static com.todoroo.andlib.Constants.BETWEEN;
import static com.todoroo.andlib.Constants.COMMA;
import static com.todoroo.andlib.Constants.LEFT_PARENTHESIS;
import static com.todoroo.andlib.Constants.RIGHT_PARENTHESIS;
import static com.todoroo.andlib.Constants.SPACE;
public class Field extends DBObject<Field> {
protected Field(String expression) {
super(expression);
}
public static Field field(String expression) {
return new Field(expression);
}
public Criterion eq(Object value) {
if(value == null)
return UnaryCriterion.isNull(this);
return UnaryCriterion.eq(this, value);
}
public Criterion neq(Object value) {
if(value == null)
return UnaryCriterion.isNotNull(this);
return UnaryCriterion.neq(this, value);
}
public Criterion gt(Object value) {
return UnaryCriterion.gt(this, value);
}
public Criterion lt(final Object value) {
return UnaryCriterion.lt(this, value);
}
public Criterion isNull() {
return UnaryCriterion.isNull(this);
}
public Criterion isNotNull() {
return UnaryCriterion.isNotNull(this);
}
public Criterion between(final Object lower, final Object upper) {
final Field field = this;
return new Criterion(null) {
@Override
protected void populate(StringBuilder sb) {
sb.append(field).append(SPACE).append(BETWEEN).append(SPACE).append(lower).append(SPACE).append(AND)
.append(SPACE).append(upper);
}
};
}
public Criterion like(final String value) {
return UnaryCriterion.like(this, value);
}
public <T> Criterion in(final T... value) {
final Field field = this;
return new Criterion(Operator.in) {
@Override
protected void populate(StringBuilder sb) {
sb.append(field).append(SPACE).append(Operator.in).append(SPACE).append(LEFT_PARENTHESIS);
for (T t : value) {
sb.append(t.toString()).append(COMMA);
}
sb.deleteCharAt(sb.length() - 1).append(RIGHT_PARENTHESIS);
}
};
}
public Criterion in(final Query query) {
final Field field = this;
return new Criterion(Operator.in) {
@Override
protected void populate(StringBuilder sb) {
sb.append(field).append(SPACE).append(Operator.in).append(SPACE).append(LEFT_PARENTHESIS).append(query)
.append(RIGHT_PARENTHESIS);
}
};
}
}
package com.todoroo.andlib;
import static com.todoroo.andlib.Constants.AND;
import static com.todoroo.andlib.Constants.BETWEEN;
import static com.todoroo.andlib.Constants.COMMA;
import static com.todoroo.andlib.Constants.LEFT_PARENTHESIS;
import static com.todoroo.andlib.Constants.RIGHT_PARENTHESIS;
import static com.todoroo.andlib.Constants.SPACE;
public class Field extends DBObject<Field> {
protected Field(String expression) {
super(expression);
}
public static Field field(String expression) {
return new Field(expression);
}
public Criterion eq(Object value) {
if(value == null)
return UnaryCriterion.isNull(this);
return UnaryCriterion.eq(this, value);
}
public Criterion neq(Object value) {
if(value == null)
return UnaryCriterion.isNotNull(this);
return UnaryCriterion.neq(this, value);
}
public Criterion gt(Object value) {
return UnaryCriterion.gt(this, value);
}
public Criterion lt(final Object value) {
return UnaryCriterion.lt(this, value);
}
public Criterion isNull() {
return UnaryCriterion.isNull(this);
}
public Criterion isNotNull() {
return UnaryCriterion.isNotNull(this);
}
public Criterion between(final Object lower, final Object upper) {
final Field field = this;
return new Criterion(null) {
@Override
protected void populate(StringBuilder sb) {
sb.append(field).append(SPACE).append(BETWEEN).append(SPACE).append(lower).append(SPACE).append(AND)
.append(SPACE).append(upper);
}
};
}
public Criterion like(final String value) {
return UnaryCriterion.like(this, value);
}
public <T> Criterion in(final T... value) {
final Field field = this;
return new Criterion(Operator.in) {
@Override
protected void populate(StringBuilder sb) {
sb.append(field).append(SPACE).append(Operator.in).append(SPACE).append(LEFT_PARENTHESIS);
for (T t : value) {
sb.append(t.toString()).append(COMMA);
}
sb.deleteCharAt(sb.length() - 1).append(RIGHT_PARENTHESIS);
}
};
}
public Criterion in(final Query query) {
final Field field = this;
return new Criterion(Operator.in) {
@Override
protected void populate(StringBuilder sb) {
sb.append(field).append(SPACE).append(Operator.in).append(SPACE).append(LEFT_PARENTHESIS).append(query)
.append(RIGHT_PARENTHESIS);
}
};
}
}

@ -1,14 +1,14 @@
package com.todoroo.andlib;
import java.util.ArrayList;
import java.util.List;
public class GroupBy {
private List<Field> fields = new ArrayList<Field>();
public static GroupBy groupBy(Field field) {
GroupBy groupBy = new GroupBy();
groupBy.fields.add(field);
return groupBy;
}
}
package com.todoroo.andlib;
import java.util.ArrayList;
import java.util.List;
public class GroupBy {
private List<Field> fields = new ArrayList<Field>();
public static GroupBy groupBy(Field field) {
GroupBy groupBy = new GroupBy();
groupBy.fields.add(field);
return groupBy;
}
}

@ -1,43 +1,43 @@
package com.todoroo.andlib;
import static com.todoroo.andlib.Constants.JOIN;
import static com.todoroo.andlib.Constants.ON;
import static com.todoroo.andlib.Constants.SPACE;
public class Join {
private final SqlTable joinTable;
private final JoinType joinType;
private final Criterion[] criterions;
private Join(SqlTable table, JoinType joinType, Criterion... criterions) {
joinTable = table;
this.joinType = joinType;
this.criterions = criterions;
}
public static Join inner(SqlTable expression, Criterion... criterions) {
return new Join(expression, JoinType.INNER, criterions);
}
public static Join left(SqlTable table, Criterion... criterions) {
return new Join(table, JoinType.LEFT, criterions);
}
public static Join right(SqlTable table, Criterion... criterions) {
return new Join(table, JoinType.RIGHT, criterions);
}
public static Join out(SqlTable table, Criterion... criterions) {
return new Join(table, JoinType.OUT, criterions);
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(joinType).append(SPACE).append(JOIN).append(SPACE).append(joinTable).append(SPACE).append(ON);
for (Criterion criterion : criterions) {
sb.append(SPACE).append(criterion);
}
return sb.toString();
}
}
package com.todoroo.andlib;
import static com.todoroo.andlib.Constants.JOIN;
import static com.todoroo.andlib.Constants.ON;
import static com.todoroo.andlib.Constants.SPACE;
public class Join {
private final SqlTable joinTable;
private final JoinType joinType;
private final Criterion[] criterions;
private Join(SqlTable table, JoinType joinType, Criterion... criterions) {
joinTable = table;
this.joinType = joinType;
this.criterions = criterions;
}
public static Join inner(SqlTable expression, Criterion... criterions) {
return new Join(expression, JoinType.INNER, criterions);
}
public static Join left(SqlTable table, Criterion... criterions) {
return new Join(table, JoinType.LEFT, criterions);
}
public static Join right(SqlTable table, Criterion... criterions) {
return new Join(table, JoinType.RIGHT, criterions);
}
public static Join out(SqlTable table, Criterion... criterions) {
return new Join(table, JoinType.OUT, criterions);
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(joinType).append(SPACE).append(JOIN).append(SPACE).append(joinTable).append(SPACE).append(ON);
for (Criterion criterion : criterions) {
sb.append(SPACE).append(criterion);
}
return sb.toString();
}
}

@ -1,5 +1,5 @@
package com.todoroo.andlib;
public enum JoinType {
INNER, LEFT, RIGHT, OUT
}
package com.todoroo.andlib;
public enum JoinType {
INNER, LEFT, RIGHT, OUT
}

@ -1,57 +1,57 @@
package com.todoroo.andlib;
import static com.todoroo.andlib.Constants.SPACE;
import java.util.HashMap;
import java.util.Map;
@SuppressWarnings("nls")
public final class Operator {
private final String operator;
public static final Operator eq = new Operator("=");
public static final Operator neq = new Operator("<>");
public static final Operator isNull = new Operator("IS NULL");
public static final Operator isNotNull = new Operator("IS NOT NULL");
public static final Operator gt = new Operator(">");
public static final Operator lt = new Operator("<");
public static final Operator gte = new Operator(">=");
public static final Operator lte = new Operator("<=");
public static final Operator and = new Operator("AND");
public static final Operator or = new Operator("OR");
public static final Operator not = new Operator("NOT");
public static final Operator exists = new Operator("EXISTS");
public static final Operator like = new Operator("LIKE");
public static final Operator in = new Operator("IN");
private static final Map<Operator, Operator> contraryRegistry = new HashMap<Operator, Operator>();
static {
contraryRegistry.put(eq, neq);
contraryRegistry.put(neq, eq);
contraryRegistry.put(isNull, isNotNull);
contraryRegistry.put(isNotNull, isNull);
contraryRegistry.put(gt, lte);
contraryRegistry.put(lte, gt);
contraryRegistry.put(lt, gte);
contraryRegistry.put(gte, lt);
}
private Operator(String operator) {
this.operator = operator;
}
public Operator getContrary() {
if(!contraryRegistry.containsKey(this)){
Operator opposite = new Operator(not.toString() + SPACE + this.toString());
contraryRegistry.put(this, opposite);
contraryRegistry.put(opposite, this);
}
return contraryRegistry.get(this);
}
@Override
public String toString() {
return this.operator.toString();
}
}
package com.todoroo.andlib;
import static com.todoroo.andlib.Constants.SPACE;
import java.util.HashMap;
import java.util.Map;
@SuppressWarnings("nls")
public final class Operator {
private final String operator;
public static final Operator eq = new Operator("=");
public static final Operator neq = new Operator("<>");
public static final Operator isNull = new Operator("IS NULL");
public static final Operator isNotNull = new Operator("IS NOT NULL");
public static final Operator gt = new Operator(">");
public static final Operator lt = new Operator("<");
public static final Operator gte = new Operator(">=");
public static final Operator lte = new Operator("<=");
public static final Operator and = new Operator("AND");
public static final Operator or = new Operator("OR");
public static final Operator not = new Operator("NOT");
public static final Operator exists = new Operator("EXISTS");
public static final Operator like = new Operator("LIKE");
public static final Operator in = new Operator("IN");
private static final Map<Operator, Operator> contraryRegistry = new HashMap<Operator, Operator>();
static {
contraryRegistry.put(eq, neq);
contraryRegistry.put(neq, eq);
contraryRegistry.put(isNull, isNotNull);
contraryRegistry.put(isNotNull, isNull);
contraryRegistry.put(gt, lte);
contraryRegistry.put(lte, gt);
contraryRegistry.put(lt, gte);
contraryRegistry.put(gte, lt);
}
private Operator(String operator) {
this.operator = operator;
}
public Operator getContrary() {
if(!contraryRegistry.containsKey(this)){
Operator opposite = new Operator(not.toString() + SPACE + this.toString());
contraryRegistry.put(this, opposite);
contraryRegistry.put(opposite, this);
}
return contraryRegistry.get(this);
}
@Override
public String toString() {
return this.operator.toString();
}
}

@ -1,30 +1,30 @@
package com.todoroo.andlib;
import static com.todoroo.andlib.Constants.SPACE;
public class Order {
private final Object expression;
private final OrderType orderType;
private Order(Object expression) {
this(expression, OrderType.ASC);
}
private Order(Object expression, OrderType orderType) {
this.expression = expression;
this.orderType = orderType;
}
public static Order asc(Object expression) {
return new Order(expression);
}
public static Order desc(Object expression) {
return new Order(expression, OrderType.DESC);
}
@Override
public String toString() {
return expression + SPACE + orderType;
}
}
package com.todoroo.andlib;
import static com.todoroo.andlib.Constants.SPACE;
public class Order {
private final Object expression;
private final OrderType orderType;
private Order(Object expression) {
this(expression, OrderType.ASC);
}
private Order(Object expression, OrderType orderType) {
this.expression = expression;
this.orderType = orderType;
}
public static Order asc(Object expression) {
return new Order(expression);
}
public static Order desc(Object expression) {
return new Order(expression, OrderType.DESC);
}
@Override
public String toString() {
return expression + SPACE + orderType;
}
}

@ -1,5 +1,5 @@
package com.todoroo.andlib;
public enum OrderType {
DESC, ASC
}
package com.todoroo.andlib;
public enum OrderType {
DESC, ASC
}

@ -1,192 +1,192 @@
package com.todoroo.andlib;
import static com.todoroo.andlib.Constants.ALL;
import static com.todoroo.andlib.Constants.COMMA;
import static com.todoroo.andlib.Constants.FROM;
import static com.todoroo.andlib.Constants.GROUP_BY;
import static com.todoroo.andlib.Constants.LEFT_PARENTHESIS;
import static com.todoroo.andlib.Constants.ORDER_BY;
import static com.todoroo.andlib.Constants.RIGHT_PARENTHESIS;
import static com.todoroo.andlib.Constants.SELECT;
import static com.todoroo.andlib.Constants.SPACE;
import static com.todoroo.andlib.Constants.WHERE;
import static com.todoroo.andlib.SqlTable.table;
import static java.util.Arrays.asList;
import java.util.ArrayList;
import com.todoroo.astrid.data.Property;
public final class Query {
private SqlTable table;
private String queryTemplate = null;
private final ArrayList<Criterion> criterions = new ArrayList<Criterion>();
private final ArrayList<Field> fields = new ArrayList<Field>();
private final ArrayList<Join> joins = new ArrayList<Join>();
private final ArrayList<Field> groupBies = new ArrayList<Field>();
private final ArrayList<Order> orders = new ArrayList<Order>();
private final ArrayList<Criterion> havings = new ArrayList<Criterion>();
private Query(Field... fields) {
this.fields.addAll(asList(fields));
}
public static Query select(Field... fields) {
return new Query(fields);
}
public Query from(SqlTable fromTable) {
this.table = fromTable;
return this;
}
public Query join(Join... join) {
joins.addAll(asList(join));
return this;
}
public Query where(Criterion criterion) {
criterions.add(criterion);
return this;
}
public Query groupBy(Field... groupBy) {
groupBies.addAll(asList(groupBy));
return this;
}
public Query orderBy(Order... order) {
orders.addAll(asList(order));
return this;
}
public Query appendSelectFields(Property<?>... selectFields) {
this.fields.addAll(asList(selectFields));
return this;
}
@Override
public boolean equals(Object o) {
return this == o || !(o == null || getClass() != o.getClass()) && this.toString().equals(o.toString());
}
@Override
public int hashCode() {
return toString().hashCode();
}
@Override
public String toString() {
StringBuilder sql = new StringBuilder();
visitSelectClause(sql);
visitFromClause(sql);
if(queryTemplate == null) {
visitJoinClause(sql);
visitWhereClause(sql);
visitGroupByClause(sql);
visitOrderByClause(sql);
} else {
if(joins.size() > 0 || groupBies.size() > 0 || orders.size() > 0 ||
havings.size() > 0)
throw new IllegalStateException("Can't have extras AND query template"); //$NON-NLS-1$
sql.append(queryTemplate);
}
return sql.toString();
}
private void visitOrderByClause(StringBuilder sql) {
if (orders.isEmpty()) {
return;
}
sql.append(ORDER_BY);
for (Order order : orders) {
sql.append(SPACE).append(order).append(COMMA);
}
sql.deleteCharAt(sql.length() - 1).append(SPACE);
}
@SuppressWarnings("nls")
private void visitGroupByClause(StringBuilder sql) {
if (groupBies.isEmpty()) {
return;
}
sql.append(GROUP_BY);
for (Field groupBy : groupBies) {
sql.append(SPACE).append(groupBy).append(COMMA);
}
sql.deleteCharAt(sql.length() - 1).append(SPACE);
if (havings.isEmpty()) {
return;
}
sql.append("HAVING");
for (Criterion havingCriterion : havings) {
sql.append(SPACE).append(havingCriterion).append(COMMA);
}
sql.deleteCharAt(sql.length() - 1).append(SPACE);
}
private void visitWhereClause(StringBuilder sql) {
if (criterions.isEmpty()) {
return;
}
sql.append(WHERE);
for (Criterion criterion : criterions) {
sql.append(SPACE).append(criterion).append(SPACE);
}
}
private void visitJoinClause(StringBuilder sql) {
for (Join join : joins) {
sql.append(join).append(SPACE);
}
}
private void visitFromClause(StringBuilder sql) {
if (table == null) {
return;
}
sql.append(FROM).append(SPACE).append(table).append(SPACE);
}
private void visitSelectClause(StringBuilder sql) {
sql.append(SELECT).append(SPACE);
if (fields.isEmpty()) {
sql.append(ALL).append(SPACE);
return;
}
for (Field field : fields) {
sql.append(field.toStringInSelect()).append(COMMA);
}
sql.deleteCharAt(sql.length() - 1).append(SPACE);
}
public SqlTable as(String alias) {
return table(LEFT_PARENTHESIS + this.toString() + RIGHT_PARENTHESIS).as(alias);
}
public Query having(Criterion criterion) {
this.havings.add(criterion);
return this;
}
/**
* Gets a list of fields returned by this query
* @return
*/
public Property<?>[] getFields() {
return fields.toArray(new Property<?>[fields.size()]);
}
/**
* Add the SQL query template (comes after the "from")
* @param sqlQuery
* @return
*/
public Query withQueryTemplate(String template) {
queryTemplate = template;
return this;
}
}
package com.todoroo.andlib;
import static com.todoroo.andlib.Constants.ALL;
import static com.todoroo.andlib.Constants.COMMA;
import static com.todoroo.andlib.Constants.FROM;
import static com.todoroo.andlib.Constants.GROUP_BY;
import static com.todoroo.andlib.Constants.LEFT_PARENTHESIS;
import static com.todoroo.andlib.Constants.ORDER_BY;
import static com.todoroo.andlib.Constants.RIGHT_PARENTHESIS;
import static com.todoroo.andlib.Constants.SELECT;
import static com.todoroo.andlib.Constants.SPACE;
import static com.todoroo.andlib.Constants.WHERE;
import static com.todoroo.andlib.SqlTable.table;
import static java.util.Arrays.asList;
import java.util.ArrayList;
import com.todoroo.astrid.data.Property;
public final class Query {
private SqlTable table;
private String queryTemplate = null;
private final ArrayList<Criterion> criterions = new ArrayList<Criterion>();
private final ArrayList<Field> fields = new ArrayList<Field>();
private final ArrayList<Join> joins = new ArrayList<Join>();
private final ArrayList<Field> groupBies = new ArrayList<Field>();
private final ArrayList<Order> orders = new ArrayList<Order>();
private final ArrayList<Criterion> havings = new ArrayList<Criterion>();
private Query(Field... fields) {
this.fields.addAll(asList(fields));
}
public static Query select(Field... fields) {
return new Query(fields);
}
public Query from(SqlTable fromTable) {
this.table = fromTable;
return this;
}
public Query join(Join... join) {
joins.addAll(asList(join));
return this;
}
public Query where(Criterion criterion) {
criterions.add(criterion);
return this;
}
public Query groupBy(Field... groupBy) {
groupBies.addAll(asList(groupBy));
return this;
}
public Query orderBy(Order... order) {
orders.addAll(asList(order));
return this;
}
public Query appendSelectFields(Property<?>... selectFields) {
this.fields.addAll(asList(selectFields));
return this;
}
@Override
public boolean equals(Object o) {
return this == o || !(o == null || getClass() != o.getClass()) && this.toString().equals(o.toString());
}
@Override
public int hashCode() {
return toString().hashCode();
}
@Override
public String toString() {
StringBuilder sql = new StringBuilder();
visitSelectClause(sql);
visitFromClause(sql);
if(queryTemplate == null) {
visitJoinClause(sql);
visitWhereClause(sql);
visitGroupByClause(sql);
visitOrderByClause(sql);
} else {
if(joins.size() > 0 || groupBies.size() > 0 || orders.size() > 0 ||
havings.size() > 0)
throw new IllegalStateException("Can't have extras AND query template"); //$NON-NLS-1$
sql.append(queryTemplate);
}
return sql.toString();
}
private void visitOrderByClause(StringBuilder sql) {
if (orders.isEmpty()) {
return;
}
sql.append(ORDER_BY);
for (Order order : orders) {
sql.append(SPACE).append(order).append(COMMA);
}
sql.deleteCharAt(sql.length() - 1).append(SPACE);
}
@SuppressWarnings("nls")
private void visitGroupByClause(StringBuilder sql) {
if (groupBies.isEmpty()) {
return;
}
sql.append(GROUP_BY);
for (Field groupBy : groupBies) {
sql.append(SPACE).append(groupBy).append(COMMA);
}
sql.deleteCharAt(sql.length() - 1).append(SPACE);
if (havings.isEmpty()) {
return;
}
sql.append("HAVING");
for (Criterion havingCriterion : havings) {
sql.append(SPACE).append(havingCriterion).append(COMMA);
}
sql.deleteCharAt(sql.length() - 1).append(SPACE);
}
private void visitWhereClause(StringBuilder sql) {
if (criterions.isEmpty()) {
return;
}
sql.append(WHERE);
for (Criterion criterion : criterions) {
sql.append(SPACE).append(criterion).append(SPACE);
}
}
private void visitJoinClause(StringBuilder sql) {
for (Join join : joins) {
sql.append(join).append(SPACE);
}
}
private void visitFromClause(StringBuilder sql) {
if (table == null) {
return;
}
sql.append(FROM).append(SPACE).append(table).append(SPACE);
}
private void visitSelectClause(StringBuilder sql) {
sql.append(SELECT).append(SPACE);
if (fields.isEmpty()) {
sql.append(ALL).append(SPACE);
return;
}
for (Field field : fields) {
sql.append(field.toStringInSelect()).append(COMMA);
}
sql.deleteCharAt(sql.length() - 1).append(SPACE);
}
public SqlTable as(String alias) {
return table(LEFT_PARENTHESIS + this.toString() + RIGHT_PARENTHESIS).as(alias);
}
public Query having(Criterion criterion) {
this.havings.add(criterion);
return this;
}
/**
* Gets a list of fields returned by this query
* @return
*/
public Property<?>[] getFields() {
return fields.toArray(new Property<?>[fields.size()]);
}
/**
* Add the SQL query template (comes after the "from")
* @param sqlQuery
* @return
*/
public Query withQueryTemplate(String template) {
queryTemplate = template;
return this;
}
}

@ -1,117 +1,117 @@
package com.todoroo.andlib;
import static com.todoroo.andlib.Constants.COMMA;
import static com.todoroo.andlib.Constants.GROUP_BY;
import static com.todoroo.andlib.Constants.LIMIT;
import static com.todoroo.andlib.Constants.ORDER_BY;
import static com.todoroo.andlib.Constants.SPACE;
import static com.todoroo.andlib.Constants.WHERE;
import static java.util.Arrays.asList;
import java.util.ArrayList;
/**
* Query Template returns a bunch of criteria that allows a query to be
* constructed
*
* @author Tim Su <tim@todoroo.com>
*
*/
public final class QueryTemplate {
private final ArrayList<Criterion> criterions = new ArrayList<Criterion>();
private final ArrayList<Join> joins = new ArrayList<Join>();
private final ArrayList<Field> groupBies = new ArrayList<Field>();
private final ArrayList<Order> orders = new ArrayList<Order>();
private final ArrayList<Criterion> havings = new ArrayList<Criterion>();
private Integer limit = null;
public QueryTemplate join(Join... join) {
joins.addAll(asList(join));
return this;
}
public QueryTemplate where(Criterion criterion) {
criterions.add(criterion);
return this;
}
public QueryTemplate groupBy(Field... groupBy) {
groupBies.addAll(asList(groupBy));
return this;
}
public QueryTemplate orderBy(Order... order) {
orders.addAll(asList(order));
return this;
}
@Override
public String toString() {
StringBuilder sql = new StringBuilder();
visitJoinClause(sql);
visitWhereClause(sql);
visitGroupByClause(sql);
visitOrderByClause(sql);
if(limit != null)
sql.append(LIMIT).append(SPACE).append(limit);
return sql.toString();
}
private void visitOrderByClause(StringBuilder sql) {
if (orders.isEmpty()) {
return;
}
sql.append(ORDER_BY);
for (Order order : orders) {
sql.append(SPACE).append(order).append(COMMA);
}
sql.deleteCharAt(sql.length() - 1).append(SPACE);
}
@SuppressWarnings("nls")
private void visitGroupByClause(StringBuilder sql) {
if (groupBies.isEmpty()) {
return;
}
sql.append(GROUP_BY);
for (Field groupBy : groupBies) {
sql.append(SPACE).append(groupBy).append(COMMA);
}
sql.deleteCharAt(sql.length() - 1).append(SPACE);
if (havings.isEmpty()) {
return;
}
sql.append("HAVING");
for (Criterion havingCriterion : havings) {
sql.append(SPACE).append(havingCriterion).append(COMMA);
}
sql.deleteCharAt(sql.length() - 1).append(SPACE);
}
private void visitWhereClause(StringBuilder sql) {
if (criterions.isEmpty()) {
return;
}
sql.append(WHERE);
for (Criterion criterion : criterions) {
sql.append(SPACE).append(criterion).append(SPACE);
}
}
private void visitJoinClause(StringBuilder sql) {
for (Join join : joins) {
sql.append(join).append(SPACE);
}
}
public QueryTemplate having(Criterion criterion) {
this.havings.add(criterion);
return this;
}
public QueryTemplate limit(int limitValue) {
this.limit = limitValue;
return this;
}
}
package com.todoroo.andlib;
import static com.todoroo.andlib.Constants.COMMA;
import static com.todoroo.andlib.Constants.GROUP_BY;
import static com.todoroo.andlib.Constants.LIMIT;
import static com.todoroo.andlib.Constants.ORDER_BY;
import static com.todoroo.andlib.Constants.SPACE;
import static com.todoroo.andlib.Constants.WHERE;
import static java.util.Arrays.asList;
import java.util.ArrayList;
/**
* Query Template returns a bunch of criteria that allows a query to be
* constructed
*
* @author Tim Su <tim@todoroo.com>
*
*/
public final class QueryTemplate {
private final ArrayList<Criterion> criterions = new ArrayList<Criterion>();
private final ArrayList<Join> joins = new ArrayList<Join>();
private final ArrayList<Field> groupBies = new ArrayList<Field>();
private final ArrayList<Order> orders = new ArrayList<Order>();
private final ArrayList<Criterion> havings = new ArrayList<Criterion>();
private Integer limit = null;
public QueryTemplate join(Join... join) {
joins.addAll(asList(join));
return this;
}
public QueryTemplate where(Criterion criterion) {
criterions.add(criterion);
return this;
}
public QueryTemplate groupBy(Field... groupBy) {
groupBies.addAll(asList(groupBy));
return this;
}
public QueryTemplate orderBy(Order... order) {
orders.addAll(asList(order));
return this;
}
@Override
public String toString() {
StringBuilder sql = new StringBuilder();
visitJoinClause(sql);
visitWhereClause(sql);
visitGroupByClause(sql);
visitOrderByClause(sql);
if(limit != null)
sql.append(LIMIT).append(SPACE).append(limit);
return sql.toString();
}
private void visitOrderByClause(StringBuilder sql) {
if (orders.isEmpty()) {
return;
}
sql.append(ORDER_BY);
for (Order order : orders) {
sql.append(SPACE).append(order).append(COMMA);
}
sql.deleteCharAt(sql.length() - 1).append(SPACE);
}
@SuppressWarnings("nls")
private void visitGroupByClause(StringBuilder sql) {
if (groupBies.isEmpty()) {
return;
}
sql.append(GROUP_BY);
for (Field groupBy : groupBies) {
sql.append(SPACE).append(groupBy).append(COMMA);
}
sql.deleteCharAt(sql.length() - 1).append(SPACE);
if (havings.isEmpty()) {
return;
}
sql.append("HAVING");
for (Criterion havingCriterion : havings) {
sql.append(SPACE).append(havingCriterion).append(COMMA);
}
sql.deleteCharAt(sql.length() - 1).append(SPACE);
}
private void visitWhereClause(StringBuilder sql) {
if (criterions.isEmpty()) {
return;
}
sql.append(WHERE);
for (Criterion criterion : criterions) {
sql.append(SPACE).append(criterion).append(SPACE);
}
}
private void visitJoinClause(StringBuilder sql) {
for (Join join : joins) {
sql.append(join).append(SPACE);
}
}
public QueryTemplate having(Criterion criterion) {
this.havings.add(criterion);
return this;
}
public QueryTemplate limit(int limitValue) {
this.limit = limitValue;
return this;
}
}

@ -1,20 +1,20 @@
package com.todoroo.andlib;
public class SqlTable extends DBObject<SqlTable> {
protected SqlTable(String expression) {
super(expression);
}
public static SqlTable table(String table) {
return new SqlTable(table);
}
@SuppressWarnings("nls")
protected String fieldExpression(String fieldName) {
if (hasAlias()) {
return alias + "." + fieldName;
}
return expression+"."+fieldName;
}
}
package com.todoroo.andlib;
public class SqlTable extends DBObject<SqlTable> {
protected SqlTable(String expression) {
super(expression);
}
public static SqlTable table(String table) {
return new SqlTable(table);
}
@SuppressWarnings("nls")
protected String fieldExpression(String fieldName) {
if (hasAlias()) {
return alias + "." + fieldName;
}
return expression+"."+fieldName;
}
}

@ -1,92 +1,92 @@
package com.todoroo.andlib;
import static com.todoroo.andlib.Constants.SPACE;
public class UnaryCriterion extends Criterion {
protected final Field expression;
protected final Object value;
UnaryCriterion(Field expression, Operator operator, Object value) {
super(operator);
this.expression = expression;
this.value = value;
}
@Override
protected void populate(StringBuilder sb) {
beforePopulateOperator(sb);
populateOperator(sb);
afterPopulateOperator(sb);
}
public static Criterion eq(Field expression, Object value) {
return new UnaryCriterion(expression, Operator.eq, value);
}
protected void beforePopulateOperator(StringBuilder sb) {
sb.append(expression);
}
protected void populateOperator(StringBuilder sb) {
sb.append(operator);
}
@SuppressWarnings("nls")
protected void afterPopulateOperator(StringBuilder sb) {
if(value == null)
return;
else if(value instanceof String)
sb.append("'").append(sanitize((String) value)).append("'");
else
sb.append(value);
}
/**
* Sanitize the given input for SQL
* @param input
* @return
*/
@SuppressWarnings("nls")
public static String sanitize(String input) {
return input.replace("\\", "\\\\").replace("'", "\\'");
}
public static Criterion neq(Field field, Object value) {
return new UnaryCriterion(field, Operator.neq, value);
}
public static Criterion gt(Field field, Object value) {
return new UnaryCriterion(field, Operator.gt, value);
}
public static Criterion lt(Field field, Object value) {
return new UnaryCriterion(field, Operator.lt, value);
}
public static Criterion isNull(Field field) {
return new UnaryCriterion(field, Operator.isNull, null) {
@Override
protected void populateOperator(StringBuilder sb) {
sb.append(SPACE).append(operator);
}
};
}
public static Criterion isNotNull(Field field) {
return new UnaryCriterion(field, Operator.isNotNull, null) {
@Override
protected void populateOperator(StringBuilder sb) {
sb.append(SPACE).append(operator);
}
};
}
public static Criterion like(Field field, String value) {
return new UnaryCriterion(field, Operator.like, value) {
@Override
protected void populateOperator(StringBuilder sb) {
sb.append(SPACE).append(operator).append(SPACE);
}
};
}
}
package com.todoroo.andlib;
import static com.todoroo.andlib.Constants.SPACE;
public class UnaryCriterion extends Criterion {
protected final Field expression;
protected final Object value;
UnaryCriterion(Field expression, Operator operator, Object value) {
super(operator);
this.expression = expression;
this.value = value;
}
@Override
protected void populate(StringBuilder sb) {
beforePopulateOperator(sb);
populateOperator(sb);
afterPopulateOperator(sb);
}
public static Criterion eq(Field expression, Object value) {
return new UnaryCriterion(expression, Operator.eq, value);
}
protected void beforePopulateOperator(StringBuilder sb) {
sb.append(expression);
}
protected void populateOperator(StringBuilder sb) {
sb.append(operator);
}
@SuppressWarnings("nls")
protected void afterPopulateOperator(StringBuilder sb) {
if(value == null)
return;
else if(value instanceof String)
sb.append("'").append(sanitize((String) value)).append("'");
else
sb.append(value);
}
/**
* Sanitize the given input for SQL
* @param input
* @return
*/
@SuppressWarnings("nls")
public static String sanitize(String input) {
return input.replace("\\", "\\\\").replace("'", "\\'");
}
public static Criterion neq(Field field, Object value) {
return new UnaryCriterion(field, Operator.neq, value);
}
public static Criterion gt(Field field, Object value) {
return new UnaryCriterion(field, Operator.gt, value);
}
public static Criterion lt(Field field, Object value) {
return new UnaryCriterion(field, Operator.lt, value);
}
public static Criterion isNull(Field field) {
return new UnaryCriterion(field, Operator.isNull, null) {
@Override
protected void populateOperator(StringBuilder sb) {
sb.append(SPACE).append(operator);
}
};
}
public static Criterion isNotNull(Field field) {
return new UnaryCriterion(field, Operator.isNotNull, null) {
@Override
protected void populateOperator(StringBuilder sb) {
sb.append(SPACE).append(operator);
}
};
}
public static Criterion like(Field field, String value) {
return new UnaryCriterion(field, Operator.like, value) {
@Override
protected void populateOperator(StringBuilder sb) {
sb.append(SPACE).append(operator).append(SPACE);
}
};
}
}

Loading…
Cancel
Save