Skip to content

Instantly share code, notes, and snippets.

@martinnedopil
Created October 1, 2014 05:28
Show Gist options
  • Save martinnedopil/c81d0ad36f800501e84e to your computer and use it in GitHub Desktop.
Save martinnedopil/c81d0ad36f800501e84e to your computer and use it in GitHub Desktop.
DbQuery files to implement leftJoin
/**
* Copyright 2014 Ricky Tobing
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance insert the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.bingzer.android.dbv.queries;
import com.bingzer.android.dbv.contracts.Distinguishable;
import com.bingzer.android.dbv.contracts.Joinable;
import com.bingzer.android.dbv.contracts.Selectable;
/**
* Represents an inner join statement
* <p>
* Find a complete <code>Wiki</code> and documentation here:<br/>
* <a href="https://github.com/bingzer/DbQuery/wiki">https://github.com/bingzer/DbQuery/wiki</a>
* </p>
*
* @see OuterJoin
*/
public interface InnerJoin extends
Joinable, Joinable.Inner, Joinable.Outer, Joinable.Left, Selectable, Select, Distinguishable {
}
/**
* Copyright 2014 Ricky Tobing
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.bingzer.android.dbv.internal.queries;
import com.bingzer.android.dbv.internal.Table;
import com.bingzer.android.dbv.queries.InnerJoin;
/**
* Created by Ricky on 4/26/2014.
*/
public abstract class InnerJoinImpl extends JoinImpl implements InnerJoin {
public InnerJoinImpl(Table table, String tableNameToJoin, String onClause) {
super(table, "INNER JOIN", tableNameToJoin, onClause);
}
}
/**
* Copyright 2014 Ricky Tobing
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.bingzer.android.dbv;
import com.bingzer.android.dbv.contracts.Alterable;
import com.bingzer.android.dbv.contracts.Countable;
import com.bingzer.android.dbv.contracts.Deletable;
import com.bingzer.android.dbv.contracts.Distinguishable;
import com.bingzer.android.dbv.contracts.Droppable;
import com.bingzer.android.dbv.contracts.Function;
import com.bingzer.android.dbv.contracts.Insertable;
import com.bingzer.android.dbv.contracts.Joinable;
import com.bingzer.android.dbv.contracts.PrimaryKeyIdentifier;
import com.bingzer.android.dbv.contracts.RawQueryable;
import com.bingzer.android.dbv.contracts.SelectIdentifiable;
import com.bingzer.android.dbv.contracts.Selectable;
import com.bingzer.android.dbv.contracts.Tangible;
import com.bingzer.android.dbv.contracts.Unionable;
import com.bingzer.android.dbv.contracts.Updatable;
import java.util.List;
/**
* Represents a table. {@link com.bingzer.android.dbv.ITable} provides full
* access to achieve common <code>CRUD</code> tasks.
*
* <p>
* {@link com.bingzer.android.dbv.ITable} object, once created, is automatically
* cached inside the {@link com.bingzer.android.dbv.IDatabase}.
* Therefore there's no need to reference it outside. Most of the time
* <code>db.get("tableName").<someMethod>()</code> is more preferable to use.
* </p>
*
* <p>
* {@link com.bingzer.android.dbv.ITable} does not store any table structure
* or any data whatsoever. It only stores its name, alias (if any) and column names.
* So it's easy on the memory usage.
* </p>
*
* <p>
* {@link com.bingzer.android.dbv.ITable} provides common methods to perform many
* <code>CRUD</code> and other common tasks such as (functions, count, etc...).
* This is the object that you will reference to access and manipulate the data with.
* </p>
*
* <p>
* <b>Related operations:</b>
* <ul>
* <li>{@link com.bingzer.android.dbv.queries.Select Select}</li>
* <li>{@link com.bingzer.android.dbv.queries.Insert Insert}</li>
* <li>{@link com.bingzer.android.dbv.queries.Update Update}</li>
* <li>{@link com.bingzer.android.dbv.queries.Delete Delete}</li>
* <li>{@link com.bingzer.android.dbv.queries.InnerJoin InnerJoin}</li>
* <li>{@link com.bingzer.android.dbv.queries.OuterJoin OuterJoin}</li>
* <li>{@link com.bingzer.android.dbv.queries.Union Union}</li>
* <li>{@link com.bingzer.android.dbv.queries.GroupBy GroupBy}</li>
* <li>{@link com.bingzer.android.dbv.queries.Having Having}</li>
* </ul>
* </p>
* <p>
* Find a complete <code>Wiki</code> and documentation here:<br/>
* <a href="https://github.com/bingzer/DbQuery/wiki">https://github.com/bingzer/DbQuery/wiki</a>
* </p>
* <p>
* <b>Warning:</b><br/>
* <code>DbQuery</code> will <code>assume</code>
* that every table will follow a naming convention for
* their identifier scheme. By default, "Id" is assigned
* automatically. For more information see {@link IConfig}
* </p>
*
* @version 2.0
* @see IDatabase
* @see IConfig
* @author Ricky Tobing
*/
public interface ITable extends
PrimaryKeyIdentifier,
Selectable, SelectIdentifiable, Distinguishable,
Insertable, Deletable, Updatable,
Joinable.Inner, Joinable.Outer, Joinable.Left,
RawQueryable, Countable, Tangible,
Droppable, Function,
Alterable, Unionable {
/**
* Returns the name of this table
* @return the name of the table
*/
String getName();
/**
* Sets the current alias of this table
* @param alias sets the alias (maybe null)
*/
void setAlias(String alias);
/**
* This table alias
* @return returns the alias (null if none)
*/
String getAlias();
/**
* Returns the column name
* @return the list of columns
*/
List<String> getColumns();
/**
* Returns the column count
* @return the column count
*/
int getColumnCount();
//////////////////////////////////////////////////////////////////////////////////////////////
/**
* The model of this table
*/
public static interface Model {
/**
* Returns the name of this table
* @return the name of this table
*/
String getName();
/**
* Adds a column
* @param columnName the column name
* @param dataType data type (i.e: INTEGER, TEXT, BLOB, etc..)
* @return this
*/
Model add(String columnName, String dataType);
/**
* Adds a column. See SQLite documentation for columnDefinition
* @param columnName the column name
* @param dataType data type (i.e: INTEGER, TEXT, BLOB, etc..)
* @param columnDefinition column definiation (i.e: nullable, primary key, autoincrement, etc...)
* @return this
*/
Model add(String columnName, String dataType, String columnDefinition);
/**
* Create index on the specified column name. The index name will always be
* <code>[TABLE_NAME]_[COLUMN_NAME]_IDX</code>
* <code>
* <pre>
* Model.add("Person")
* .addPrimaryKey("Id") // Column Id
* .addText("Name", "not null") // Column Name
* .addInteger("Age") // Column Age
* .addText("Address") // Column Address
* .index("Name", "Age") // Index of Column Name and Age
* </pre>
* </code>
* @param columnNames array of column names in this table to index
* @return this
*/
Model index(String... columnNames);
/**
* Flags to append "IF NOT EXISTS" before create
* @return this
*/
Model ifNotExists();
/**
* Foreign key. Create a foreign key references get a column get this current table
* to another column on another table. Note that when you call this method,
* the referenced table and column needs to exists.
* <code>targetColumn</code> must be defined as <code>[TableName].[ColumnName]</code>
*
* @param columnName the referencing column name (get this table)
* @param targetColumn the referenced column name (get the referenced table)
* {@code targetColumn} must be defined as
* <code>[TableName].[ColumnName]</code>
* (i.e: Customers.Id, Products.Number)
*/
Model foreignKey(String columnName, String targetColumn);
/**
* Foreign key. Create a foreign key references get a column get this current table
* to another column on another table. Note that when you call this method,
* the referenced table and column needs to exists.
* <code>targetColumn</code> must be defined as <code>[TableName].[ColumnName]</code>
*
* @param columnName the referencing column name (get this table)
* @param targetColumn the referenced column name (get the referenced table)
* {@code targetColumn} must be defined as
* <code>[TableName].[ColumnName]</code>
* (i.e: Customers.Id, Products.Number)
* @param actionClause additional clause any of these
* "NO ACTION", "RESTRICT", "SET NULL", "SET DEFAULT" or "CASCADE"
* null means "NO ACTION"
*
*/
Model foreignKey(String columnName, String targetColumn, String actionClause);
/**
* Foreign key. Create a foreign key references get a column get this current table
* to another column on another table. Note that when you call this method,
* the referenced table and column needs to exists.
*
* @param columnName the referencing column name (get this table)
* @param targetTable the referenced table (i.e: Customers, Products)
* @param targetColumn the referenced column name (get the referenced table)
* (i.e: Id, Number)
* @param actionClause additional clause any of these
* "NO ACTION", "RESTRICT", "SET NULL", "SET DEFAULT" or "CASCADE"
* null means "NO ACTION"
*/
Model foreignKey(String columnName, String targetTable, String targetColumn, String actionClause);
//////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////
/**
* Convenient way to adding primary key column.
* Primary key always have
* <code>primary key autoincrement</code> column definition
* @param columnName column name
* @return this
*/
Model addPrimaryKey(String columnName);
/**
* Convenient method to calling
* <code>add(columnName, "TEXT")</code>
* @param columnName the column name
* @return this
*/
Model addText(String columnName);
/**
* Convenient method to calling
* <code>add(columnName, "TEXT", columnDefinition)</code>
* @param columnName the column name
* @param columnDefinition column definition
* @return this
*/
Model addText(String columnName, String columnDefinition);
/**
* Convenient method to calling
* <code>add(columnName, "INTEGER")</code>
* @param columnName the column name
* @return this
*/
Model addInteger(String columnName);
/**
* Convenient method to calling
* <code>add(columnName, "INTEGER", columnDefinition)</code>
* @param columnName the column name
* @param columnDefinition column definition
* @return this
*/
Model addInteger(String columnName, String columnDefinition);
/**
* Convenient method to calling
* <code>add(columnName, "REAL")</code>
* @param columnName the column name
* @return this
*/
Model addReal(String columnName);
/**
* Convenient method to calling
* <code>add(columnName, "REAL", columnDefinition)</code>
* @param columnName the column name
* @param columnDefinition column definition
* @return this
*/
Model addReal(String columnName, String columnDefinition);
/**
* Convenient method to calling
* <code>add(columnName, "NUMERIC")</code>
* @param columnName the column name
* @return this
*/
Model addNumeric(String columnName);
/**
* Convenient method to calling
* <code>add(columnName, "NUMERIC", columnDefinition)</code>
* @param columnName the column name
* @param columnDefinition column definition
* @return this
*/
Model addNumeric(String columnName, String columnDefinition);
/**
* Convenient method to calling
* <code>add(columnName, "BLOB")</code>
* @param columnName the column name
* @return this
*/
Model addBlob(String columnName);
/**
* Convenient method to calling
* <code>add(columnName, "BLOB", columnDefinition)</code>
* @param columnName the column name
* @param columnDefinition column definition
* @return this
*/
Model addBlob(String columnName, String columnDefinition);
}
//////////////////////////////////////////////////////////////////////////////////////////////
/**
* Handles all alteration (renaming table, add columns, etc...)
*/
public static interface Alter {
/**
* Rename current table to the <code>newName</code>
* @param newName new name of this table
* @return this
*/
Alter rename(String newName);
/**
* Adds a new column to this table.
* @param columnName new column name
* @param dataType data type
* @return this
*/
Alter addColumn(String columnName, String dataType);
/**
* Adds a new column to this table.
* @param columnName new column name
* @param dataType data type
* @param columnDefinition column definition
* @return this
*/
Alter addColumn(String columnName, String dataType, String columnDefinition);
/**
* Removes a column (Not supported).
* Will throw {@link UnsupportedOperationException}
* <b>SQLite does not support this method</b>.
* @param columnName columnName to remove
* @return this
*/
Alter removeColumn(String columnName);
}
}
/**
* Copyright 2013 Ricky Tobing
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance insert the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.bingzer.android.dbv.contracts;
import com.bingzer.android.dbv.queries.InnerJoin;
import com.bingzer.android.dbv.queries.LeftJoin;
import com.bingzer.android.dbv.queries.OuterJoin;
/**
* Created by Ricky Tobing on 7/17/13.
*/
public interface Joinable {
/**
* Inner-Join
*/
public static interface Inner extends Joinable{
/**
* Inner join a table
* @param tableName table name to join
* @param onClause the on clause
* @return {@link com.bingzer.android.dbv.queries.InnerJoin}
*/
InnerJoin join(String tableName, String onClause);
/**
* Inner join a table
* @param tableName table name to join
* @param column1 first column
* @param column2 second column
* @return {@link com.bingzer.android.dbv.queries.InnerJoin}
*/
InnerJoin join(String tableName, String column1, String column2);
}
public static interface Left extends Joinable{
/**
* Left join a table
* @param tableName table name to join
* @param onClause the on clause
* @return {@link com.bingzer.android.dbv.queries.LeftJoin}
*/
LeftJoin leftJoin(String tableName, String onClause);
/**
* Left join a table
* @param tableName table name to join
* @param column1 first column
* @param column2 second column
* @return {@link com.bingzer.android.dbv.queries.LeftJoin}
*/
LeftJoin leftJoin(String tableName, String column1, String column2);
}
/**
* Outer-Join
*/
public static interface Outer extends Joinable{
/**
* Outer join a table
* @param tableName table name to join
* @param onClause the on clause
* @return {@link com.bingzer.android.dbv.queries.OuterJoin}
*/
OuterJoin outerJoin(String tableName, String onClause);
/**
* Inner join a table
* @param tableName table name to join
* @param column1 first column
* @param column2 second column
* @return {@link com.bingzer.android.dbv.queries.OuterJoin}
*/
OuterJoin outerJoin(String tableName, String column1, String column2);
}
}
/**
* Copyright 2014 Ricky Tobing
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.bingzer.android.dbv.internal.queries;
import com.bingzer.android.dbv.internal.Database;
import com.bingzer.android.dbv.internal.Table;
import com.bingzer.android.dbv.contracts.Distinguishable;
import com.bingzer.android.dbv.contracts.Selectable;
import com.bingzer.android.dbv.queries.InnerJoin;
import com.bingzer.android.dbv.queries.LeftJoin;
import com.bingzer.android.dbv.queries.OuterJoin;
import com.bingzer.android.dbv.queries.Select;
import java.util.Locale;
/**
* Created by Ricky on 4/26/2014.
*/
public abstract class JoinImpl extends SelectImpl implements InnerJoin, LeftJoin, OuterJoin, Selectable, Distinguishable {
private final Table table;
protected StringBuilder joinBuilder;
public JoinImpl(Table table, String joinType, String tableNameToJoin, String onClause){
super( table);
this.table = table;
this.joinBuilder = new StringBuilder();
if(onClause.toLowerCase(Locale.getDefault()).startsWith("on "))
this.joinBuilder.append(Database.SPACE).append(joinType).append(Database.SPACE)
.append(tableNameToJoin).append(Database.SPACE).append(onClause);
else
this.joinBuilder.append(Database.SPACE).append(joinType).append(Database.SPACE)
.append(tableNameToJoin).append(" ON ").append(onClause);
}
@Override
public Select select(int top, String condition) {
consume(table.select(top, condition));
return this;
}
@Override
public Select select(String condition) {
consume(table.select(condition));
return this;
}
@Override
public Select select(long id) {
consume(table.select(id));
return this;
}
@Override
public Select select(long... ids) {
consume(table.select(ids));
return this;
}
@Override
public Select select(String whereClause, Object... args) {
consume(table.select(whereClause, args));
return this;
}
@Override
public Select select(int top, String whereClause, Object... args) {
consume(table.select(top, whereClause, args));
return this;
}
@Override
public Select selectDistinct() {
consume(table.selectDistinct(null));
return this;
}
@Override
public Select selectDistinct(String condition) {
consume(table.selectDistinct(condition));
return this;
}
@Override
public Select selectDistinct(String whereClause, Object... args) {
consume(table.selectDistinct(whereClause, args));
return this;
}
@Override
public Select selectDistinct(int top) {
consume(table.selectDistinct(top));
return this;
}
@Override
public Select selectDistinct(int top, String condition) {
consume(table.selectDistinct(top, condition));
return this;
}
@Override
public Select selectDistinct(int top, String whereClause, Object... args) {
consume(table.selectDistinct(top, whereClause, args));
return this;
}
@Override
public String toString(){
StringBuilder sql = new StringBuilder();
sql.append(selectString);
sql.append(columnString).append(Database.SPACE);
sql.append(fromString).append(Database.SPACE);
// join builder
sql.append(joinBuilder).append(Database.SPACE);
// where
sql.append(whereString).append(Database.SPACE);
// group by + having
if(groupByString != null) sql.append(Database.SPACE).append(groupByString);
if(havingString != null) sql.append(Database.SPACE).append(havingString);
// order by
if(orderByString != null) sql.append(Database.SPACE).append(orderByString);
// limit
if(limitString != null) sql.append(Database.SPACE).append(limitString);
return sql.toString();
}
@Override
public InnerJoin join(String tableName, String onClause) {
if(onClause.toLowerCase(Locale.getDefault()).startsWith("on "))
this.joinBuilder.append(Database.SPACE).append("INNER JOIN").append(Database.SPACE)
.append(tableName).append(Database.SPACE).append(onClause);
else
this.joinBuilder.append(Database.SPACE).append("INNER JOIN").append(Database.SPACE)
.append(tableName).append(" ON ").append(onClause);
return this;
}
@Override
public InnerJoin join(String tableName, String column1, String column2) {
return join(tableName, column1 + " = " + column2);
}
@Override
public OuterJoin outerJoin(String tableName, String onClause) {
if(onClause.toLowerCase(Locale.getDefault()).startsWith("on "))
this.joinBuilder.append(Database.SPACE).append("OUTER JOIN").append(Database.SPACE)
.append(tableName).append(Database.SPACE).append(onClause);
else
this.joinBuilder.append(Database.SPACE).append("OUTER JOIN").append(Database.SPACE)
.append(tableName).append(" ON ").append(onClause);
return this;
}
@Override
public OuterJoin outerJoin(String tableName, String column1, String column2) {
return outerJoin(tableName, column1 + " = " + column2);
}
@Override
public LeftJoin leftJoin(String tableName, String column1, String column2) {
return leftJoin(tableName, column1 + " = " + column2);
}
@Override
public LeftJoin leftJoin(String tableName, String onClause) {
if(onClause.toLowerCase(Locale.getDefault()).startsWith("on "))
this.joinBuilder.append(Database.SPACE).append("LEFT JOIN").append(Database.SPACE)
.append(tableName).append(Database.SPACE).append(onClause);
else
this.joinBuilder.append(Database.SPACE).append("LEFT JOIN").append(Database.SPACE)
.append(tableName).append(" ON ").append(onClause);
return this;
}
private void consume(Select select){
// consume
selectString = ((SelectImpl)select).selectString;
columnString = ((SelectImpl)select).columnString;
fromString = ((SelectImpl)select).fromString;
orderByString = ((SelectImpl)select).orderByString;
limitString = ((SelectImpl)select).limitString;
groupByString = ((SelectImpl)select).groupByString;
havingString = ((SelectImpl)select).havingString;
whereString = ((SelectImpl)select).whereString;
}
}
/**
* Copyright 2014 Ricky Tobing
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance insert the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.bingzer.android.dbv.queries;
import com.bingzer.android.dbv.contracts.Distinguishable;
import com.bingzer.android.dbv.contracts.Joinable;
import com.bingzer.android.dbv.contracts.Selectable;
/**
* Represents an inner join statement
* <p>
* Find a complete <code>Wiki</code> and documentation here:<br/>
* <a href="https://github.com/bingzer/DbQuery/wiki">https://github.com/bingzer/DbQuery/wiki</a>
* </p>
*
* @see OuterJoin
*/
public interface LeftJoin extends
Joinable, Joinable.Inner, Joinable.Outer, Joinable.Left, Selectable, Select, Distinguishable {
}
/**
* Copyright 2014 Ricky Tobing
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.bingzer.android.dbv.internal.queries;
import com.bingzer.android.dbv.internal.Table;
import com.bingzer.android.dbv.queries.LeftJoin;
/**
* Created by Ricky on 4/26/2014.
*/
public abstract class LeftJoinImpl extends JoinImpl implements LeftJoin {
public LeftJoinImpl(Table table, String tableNameToJoin, String onClause) {
super(table, "LEFT JOIN", tableNameToJoin, onClause);
}
}
/**
* Copyright 2014 Ricky Tobing
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance insert the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.bingzer.android.dbv.queries;
import com.bingzer.android.dbv.contracts.Distinguishable;
import com.bingzer.android.dbv.contracts.Joinable;
import com.bingzer.android.dbv.contracts.Selectable;
/**
* Represents an outer join statement
* <p>
* Find a complete <code>Wiki</code> and documentation here:<br/>
* <a href="https://github.com/bingzer/DbQuery/wiki">https://github.com/bingzer/DbQuery/wiki</a>
* </p>
*
* @see com.bingzer.android.dbv.queries.InnerJoin
*/
public interface OuterJoin extends
Joinable, Joinable.Inner, Joinable.Outer, Joinable.Left, Selectable, Select, Distinguishable {
}
/**
* Copyright 2014 Ricky Tobing
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.bingzer.android.dbv.internal.queries;
import com.bingzer.android.dbv.internal.Table;
import com.bingzer.android.dbv.queries.OuterJoin;
/**
* Created by Ricky on 4/26/2014.
*/
public abstract class OuterJoinImpl extends JoinImpl implements OuterJoin {
public OuterJoinImpl(Table table, String tableNameToJoin, String onClause) {
super(table, "OUTER JOIN", tableNameToJoin, onClause);
}
}
/**
* Copyright 2014 Ricky Tobing
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance insert the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.bingzer.android.dbv.internal;
import android.content.ContentValues;
import android.database.Cursor;
import com.bingzer.android.dbv.Delegate;
import com.bingzer.android.dbv.IDatabase;
import com.bingzer.android.dbv.IEntity;
import com.bingzer.android.dbv.IEntityList;
import com.bingzer.android.dbv.ITable;
import com.bingzer.android.dbv.internal.queries.AverageImpl;
import com.bingzer.android.dbv.internal.queries.ContentSet;
import com.bingzer.android.dbv.internal.queries.DeleteImpl;
import com.bingzer.android.dbv.internal.queries.DropImpl;
import com.bingzer.android.dbv.internal.queries.InnerJoinImpl;
import com.bingzer.android.dbv.internal.queries.InsertImpl;
import com.bingzer.android.dbv.internal.queries.InsertIntoImpl;
import com.bingzer.android.dbv.internal.queries.LeftJoinImpl;
import com.bingzer.android.dbv.internal.queries.MaxImpl;
import com.bingzer.android.dbv.internal.queries.MinImpl;
import com.bingzer.android.dbv.internal.queries.OuterJoinImpl;
import com.bingzer.android.dbv.internal.queries.QueryImpl;
import com.bingzer.android.dbv.internal.queries.SelectImpl;
import com.bingzer.android.dbv.internal.queries.SumImpl;
import com.bingzer.android.dbv.internal.queries.TotalImpl;
import com.bingzer.android.dbv.internal.queries.UnionImpl;
import com.bingzer.android.dbv.internal.queries.UpdateImpl;
import com.bingzer.android.dbv.queries.Average;
import com.bingzer.android.dbv.queries.Delete;
import com.bingzer.android.dbv.queries.IQuery;
import com.bingzer.android.dbv.queries.InnerJoin;
import com.bingzer.android.dbv.queries.Insert;
import com.bingzer.android.dbv.queries.InsertInto;
import com.bingzer.android.dbv.queries.LeftJoin;
import com.bingzer.android.dbv.queries.Max;
import com.bingzer.android.dbv.queries.Min;
import com.bingzer.android.dbv.queries.OuterJoin;
import com.bingzer.android.dbv.queries.Select;
import com.bingzer.android.dbv.queries.Sum;
import com.bingzer.android.dbv.queries.Total;
import com.bingzer.android.dbv.queries.Union;
import com.bingzer.android.dbv.queries.Update;
import com.bingzer.android.dbv.utils.CollectionUtils;
import com.bingzer.android.dbv.utils.ContentValuesUtils;
import com.bingzer.android.dbv.utils.Utils;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
* Created by Ricky Tobing on 7/16/13.
*/
public class Table implements ITable {
private String alias;
private String name;
private final List<String> columns;
protected final Database db;
public Table (Database db, String name){
this.name = name;
this.db = db;
this.columns = new ArrayList<String>();
queryColumns();
}
////////////////////////////////////////////////////////////////////////////////////////
@Override
public String getName() {
return name;
}
@Override
public void setAlias(String alias) {
this.alias = alias;
}
@Override
public String getAlias() {
return alias;
}
@Override
public List<String> getColumns() {
return columns;
}
@Override
public int getColumnCount() {
return columns.size();
}
@Override
public String getPrimaryKeyColumn(){
if(db.getConfig().getAppendTableNameForId()){
return getName() + db.getConfig().getIdNamingConvention();
}
return db.getConfig().getIdNamingConvention();
}
///////////////////////////////////////////////////////////////////////////////////////////////
@Override
public Select select(String condition) {
return select(condition, (Object) null);
}
@Override
public long selectId(String condition) {
return selectId(condition, (Object) null);
}
@Override
public long selectId(String whereClause, Object... args) {
long id = -1;
Cursor cursor =
select(whereClause, args)
.columns(getPrimaryKeyColumn())
.query();
if(cursor.moveToNext()){
id = cursor.getLong(0);
}
cursor.close();
return id;
}
@Override
public Select select(int top, String condition) {
return select(top, condition, (Object) null);
}
@Override
public Select select(long id) {
return select(generateParamId(id));
}
@Override
public Select select(long... ids) {
return select(generateParamInIds(ids));
}
@Override
public Select select(String whereClause, Object... args) {
return select(-1, whereClause, args);
}
@Override
public Select select(int top, String whereClause, Object... args) {
return new SelectImpl(this, top, false){
@Override public Cursor query(){
return db.sqLiteDb.rawQuery(toString(), null);
}
}.where(whereClause, args);
}
///////////////////////////////////////////////////////////////////////////////////////////////
@Override
public Select selectDistinct() {
return selectDistinct(null);
}
@Override
public Select selectDistinct(String condition) {
return selectDistinct(condition, (Object) null);
}
@Override
public Select selectDistinct(String whereClause, Object... args) {
return selectDistinct(-1, whereClause, args);
}
@Override
public Select selectDistinct(int top) {
return selectDistinct(top, null);
}
@Override
public Select selectDistinct(int top, String condition) {
return selectDistinct(top, condition, (Object) null);
}
@Override
public Select selectDistinct(int top, String whereClause, Object... args) {
return new SelectImpl(this, top, true){
@Override public Cursor query(){
return db.sqLiteDb.rawQuery(toString(), null);
}
}.where(whereClause, args);
}
///////////////////////////////////////////////////////////////////////////////////////////////
@Override
public Insert insert(final ContentValues contents) {
db.enforceReadOnly();
InsertImpl query = new InsertImpl();
query.setValue( db.sqLiteDb.insertOrThrow(getName(), null, contents) );
return query;
}
@Override
public Insert insert(String[] columns, Object[] values) {
db.enforceReadOnly();
final ContentValues contentValues = new ContentValues();
for(int i = 0; i < columns.length; i++){
ContentValuesUtils.mapContentValuesFromGenericObject(contentValues, columns[i], values[i]);
}
return insert(contentValues);
}
@Override
public Insert insert(String column, Object value) {
db.enforceReadOnly();
final ContentValues contentValues = new ContentValues();
ContentValuesUtils.mapContentValuesFromGenericObject(contentValues, column, value);
return insert(contentValues);
}
@Override
public InsertInto insertInto(String... columns) {
db.enforceReadOnly();
return new InsertIntoImpl(new ContentSet<InsertIntoImpl>() {
@Override
public void onContentValuesSet(InsertIntoImpl query, ContentValues contentValues) {
query.setValue( db.sqLiteDb.insertOrThrow(getName(), null, contentValues) );
}
}, columns);
}
@Override
@SuppressWarnings("unchecked")
public Insert insert(IEntity entity) {
db.enforceReadOnly();
// build content values..
final ContentValues contentValues = new ContentValues();
final Delegate.Mapper mapper = ContentValuesUtils.mapContentValuesFromEntity(contentValues, this, entity);
// do not insert the primary column
contentValues.remove(getPrimaryKeyColumn());
Insert insert = insert(contentValues);
// assign the newly inserted id
Delegate<Long> pkDelegate = mapper.get(getPrimaryKeyColumn());
if(pkDelegate != null){
pkDelegate.set(insert.query());
}
return insert;
}
@Override
public <E extends IEntity> Insert insert(final IEntityList<E> entityList) {
db.enforceReadOnly();
final InsertImpl query = new InsertImpl();
query.setValue(0l);
db.begin(new IDatabase.Batch() {
@Override
public void exec(IDatabase database) {
for(IEntity entity : entityList){
insert(entity).query();
query.setValue(query.query() + 1);
}
}
}).execute();
return query;
}
///////////////////////////////////////////////////////////////////////////////////////////////
@Override
public Update update(long id) {
db.enforceReadOnly();
return update(generateParamId(id));
}
@Override
public Update update(long... ids) {
db.enforceReadOnly();
return update(generateParamInIds(ids));
}
@Override
public Update update(String condition) {
db.enforceReadOnly();
return update(condition, (Object) null);
}
@Override
public Update update(final String whereClause, final Object... whereArgs) {
db.enforceReadOnly();
return new UpdateImpl(new ContentSet<UpdateImpl>() {
@Override
public void onContentValuesSet(UpdateImpl query, ContentValues contentValues) {
query.setValue(update(contentValues, whereClause, whereArgs).query());
}
});
}
@Override
public IQuery<Integer> update(IEntity entity) {
db.enforceReadOnly();
if(entity.getId() < 0) throw new IllegalArgumentException("Id has to be over than 0");
final ContentValues contentValues = ContentValuesUtils.generateContentValuesFromEntity(this, entity);
contentValues.remove(getPrimaryKeyColumn());
return update(contentValues, entity.getId());
}
@Override
public <E extends IEntity> IQuery<Integer> update(final IEntityList<E> entityList) {
db.enforceReadOnly();
final UpdateImpl query = new UpdateImpl();
boolean success = db.begin(new IDatabase.Batch() {
@Override
public void exec(IDatabase database) {
for(IEntity entity : entityList){
query.setValue( query.query() + update(entity).query() );
}
}
}).execute();
// if there's any error we should return -1
if(!success)
query.setValue(-1);
return query;
}
@Override
public IQuery<Integer> update(ContentValues contents, long id) {
db.enforceReadOnly();
return update(contents, generateParamId(id));
}
@Override
public IQuery<Integer> update(ContentValues contents, String condition) {
db.enforceReadOnly();
UpdateImpl query = new UpdateImpl();
if(contents != null && contents.size() > 0)
query.setValue( db.sqLiteDb.update(getName(), contents, condition, null) );
return query;
}
@Override
public IQuery<Integer> update(final ContentValues contents, final String whereClause, final Object... whereArgs) {
db.enforceReadOnly();
UpdateImpl query = new UpdateImpl();
String[] args = Utils.toStringArray(whereArgs);
// only update when content has something
if(contents != null && contents.size() > 0)
query.setValue( db.sqLiteDb.update(getName(), contents, whereClause, args) );
return query;
}
///////////////////////////////////////////////////////////////////////////////////////////////
@Override
public Delete delete(final long id) {
db.enforceReadOnly();
return delete(generateParamId(id));
}
@Override
public Delete delete(long... ids) {
db.enforceReadOnly();
return delete(generateParamInIds(ids));
}
@Override
public Delete delete(Collection<Long> ids) {
db.enforceReadOnly();
long[] idz = new long[CollectionUtils.size(ids)];
int counter = 0;
for (long id : ids) {
idz[counter++] = id;
}
return delete(idz);
}
@Override
public Delete delete(final String condition) {
db.enforceReadOnly();
return delete(condition, (Object)null);
}
@Override
public Delete delete(final String whereClause, final Object... whereArgs) {
db.enforceReadOnly();
DeleteImpl query = new DeleteImpl();
query.setValue(db.sqLiteDb.delete(getName(), whereClause, Utils.toStringArray((Object[]) whereArgs)));
return query;
}
@Override
public Delete delete(IEntity entity) {
db.enforceReadOnly();
return delete(entity.getId());
}
@Override
public <E extends IEntity> Delete delete(IEntityList<E> entityList) {
db.enforceReadOnly();
long[] ids = new long[CollectionUtils.size(entityList)];
int counter = 0;
for(E entity : entityList){
ids[counter++] = entity.getId();
}
return delete(ids);
}
///////////////////////////////////////////////////////////////////////////////////////////////
@Override
public boolean has(String condition) {
return has(condition, (Object) null);
}
@Override
public boolean has(long id) {
return has(generateParamId(id));
}
@Override
public boolean has(String whereClause, Object... whereArgs) {
StringBuilder sql = new StringBuilder("SELECT 1 FROM ").append(getName())
.append(" WHERE ").append(Utils.bindArgs(whereClause, whereArgs));
Cursor cursor = null;
try{
cursor = raw(sql.toString()).query();
if(cursor.moveToFirst()) return true;
}
finally {
if(cursor != null) cursor.close();
}
// nope!
return false;
}
///////////////////////////////////////////////////////////////////////////////////////////////
@Override
public int count(String condition) {
return count(condition, (Object)null);
}
@Override
public int count(String whereClause, Object... whereArgs) {
int count = 0;
StringBuilder builder = new StringBuilder("SELECT COUNT(*) FROM " + toString());
if(whereClause != null){
builder.append(" WHERE ");
builder.append(Utils.bindArgs(whereClause, whereArgs));
}
Cursor cursor = db.sqLiteDb.rawQuery(builder.toString(), null);
try{
if(cursor.moveToNext()){
count = cursor.getInt(0);
}
}
finally {
cursor.close();
}
return count;
}
@Override
public int count() {
return count(null);
}
///////////////////////////////////////////////////////////////////////////////////////////////
@Override
public IQuery<Cursor> raw(final String sql) {
return raw(sql, (String) null);
}
@Override
public IQuery<Cursor> raw(final String sql, final Object... args) {
return new QueryImpl<Cursor>(){
@Override public Cursor query(){
if(args == null || args.length == 0)
return db.sqLiteDb.rawQuery(sql, null);
else return db.sqLiteDb.rawQuery(sql, Utils.toStringArray(args));
}
};
}
///////////////////////////////////////////////////////////////////////////////////////////////
@Override
public IQuery<Boolean> drop() {
db.enforceReadOnly();
DropImpl query = new DropImpl();
try{
db.execSql("DROP TABLE " + getName());
query.setValue( true );
}
catch (Exception e){
query.setValue( false );
}
if(query.query()) db.removeTable(this);
return query;
}
///////////////////////////////////////////////////////////////////////////////////////////////
@Override
public InnerJoin join(String tableName, String onClause) {
return new InnerJoinImpl(this, tableName, onClause){
@Override public Cursor query(){
return db.sqLiteDb.rawQuery(toString(), null);
}
};
}
@Override
public InnerJoin join(String tableName, String column1, String column2) {
return join(tableName, name + "." + column1 + "=" + tableName + "." + column2);
}
@Override
public OuterJoin outerJoin(String tableName, String onClause) {
return new OuterJoinImpl(this, tableName, onClause){
@Override public Cursor query(){
return db.sqLiteDb.rawQuery(toString(), null);
}
};
}
@Override
public OuterJoin outerJoin(String tableName, String column1, String column2) {
return outerJoin(tableName, name + "." + column1 + "=" + tableName + "." + column2);
}
@Override
public LeftJoin leftJoin(String tableName, String onClause) {
return new LeftJoinImpl(this, tableName, onClause){
@Override public Cursor query(){
return db.sqLiteDb.rawQuery(toString(), null);
}
};
}
@Override
public LeftJoin leftJoin(String tableName, String column1, String column2) {
return leftJoin(tableName, name + "." + column1 + "=" + tableName + "." + column2);
}
///////////////////////////////////////////////////////////////////////////////////////////////
@Override
public Union union(Select select) {
return new UnionImpl(select, this) {
@Override
public Cursor query() {
return raw(toString()).query();
}
};
}
@Override
public Union unionAll(Select select) {
return new UnionImpl(select, this, true) {
@Override
public Cursor query() {
return raw(toString()).query();
}
};
}
///////////////////////////////////////////////////////////////////////////////////////////////
@Override
public Average avg(String columnName) {
return avg(columnName, null);
}
@Override
public Average avg(String columnName, String condition) {
AverageImpl fn = new AverageImpl(toString(), columnName, condition);
Cursor cursor = raw(fn.toString()).query();
if(cursor.moveToNext()){
fn.setValue(cursor.getDouble(0));
}
cursor.close();
return fn;
}
@Override
public Average avg(String columnName, String whereClause, Object... args) {
return avg(columnName, Utils.bindArgs(whereClause, args));
}
@Override
public Sum sum(String columnName) {
return sum(columnName, null);
}
@Override
public Sum sum(String columnName, String condition) {
SumImpl fn = new SumImpl(toString(), columnName, condition);
Cursor cursor = raw(fn.toString()).query();
if(cursor.moveToNext()){
fn.setValue(cursor.getDouble(0));
}
cursor.close();
return fn;
}
@Override
public Sum sum(String columnName, String whereClause, Object... args) {
return sum(columnName, Utils.bindArgs(whereClause, args));
}
@Override
public Total total(String columnName) {
return total(columnName, null);
}
@Override
public Total total(String columnName, String condition) {
TotalImpl fn = new TotalImpl(toString(), columnName, condition);
Cursor cursor = raw(fn.toString()).query();
if(cursor.moveToNext()){
fn.setValue(cursor.getDouble(0));
}
cursor.close();
return fn;
}
@Override
public Total total(String columnName, String whereClause, Object... args) {
return total(columnName, Utils.bindArgs(whereClause, args));
}
@Override
public Max max(String columnName) {
return max(columnName, null);
}
@Override
public Max max(String columnName, String condition) {
MaxImpl fn = new MaxImpl(toString(), columnName, condition);
Cursor cursor = raw(fn.toString()).query();
if(cursor.moveToNext()){
fn.setValue(cursor.getDouble(0));
}
cursor.close();
return fn;
}
@Override
public Max max(String columnName, String whereClause, Object... args) {
return max(columnName, Utils.bindArgs(whereClause, args));
}
@Override
public Min min(String columnName) {
return min(columnName, null);
}
@Override
public Min min(String columnName, String condition) {
MinImpl fn = new MinImpl(toString(), columnName, condition);
Cursor cursor = raw(fn.toString()).query();
if(cursor.moveToNext()){
fn.setValue(cursor.getDouble(0));
}
cursor.close();
return fn;
}
@Override
public Min min(String columnName, String whereClause, Object... args) {
return min(columnName, Utils.bindArgs(whereClause, args));
}
///////////////////////////////////////////////////////////////////////////////////////////////
@Override
public Alter alter() {
db.enforceReadOnly();
return new Alter(){
@Override
public Alter rename(String newName) {
db.execSql("ALTER TABLE " + getName() + " RENAME TO " + newName);
// quickly change our name
name = newName;
return this;
}
@Override
public Alter addColumn(String columnName, String dataType) {
return addColumn(columnName, dataType, null);
}
@Override
public Alter addColumn(String columnName, String dataType, String columnDefinition) {
Database.ColumnModel model = new Database.ColumnModel(columnName, dataType, columnDefinition);
db.execSql("ALTER TABLE " + getName() + " ADD COLUMN " + model);
// re-query columns
queryColumns();
return this;
}
@Override
public Alter removeColumn(String columnName) {
throw new UnsupportedOperationException("SQLite does not support removing columns");
}
};
}
///////////////////////////////////////////////////////////////////////////////////////////////
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Table table = (Table) o;
return name.equals(table.name);
}
@Override
public int hashCode() {
return name.hashCode();
}
@Override
public String toString(){
if(alias != null && alias.length() > 0)
return name + " " + alias;
return name;
}
///////////////////////////////////////////////////////////////////////////////////////////////
private String generateParamId(long id){
return getPrimaryKeyColumn() + " = " + id;
}
private void queryColumns(){
columns.clear();
String pragmaSql = Utils.bindArgs("PRAGMA table_info(?)", name);
Cursor cursor = db.sqLiteDb.rawQuery(pragmaSql, null);
try{
// this will throw IllegalArgumentException if not found
// meaning that this table does not exist
int nameIdx = cursor.getColumnIndexOrThrow("name");
while (cursor.moveToNext()) {
columns.add(cursor.getString(nameIdx));
}
}
finally {
cursor.close();
}
}
/**
* Generate IN(ID,ID,ID) params. if ids is empty or null
* then it will return null
* @param ids ids to generate params with
* @return string rep of IN(...) statements, null if ids is empty or null
*/
private String generateParamInIds(long... ids){
if(ids != null && ids.length > 0) {
StringBuilder builder = new StringBuilder();
builder.append(getPrimaryKeyColumn())
.append(" IN (");
for (int i = 0; i < ids.length; i++) {
builder.append(ids[i]);
if (i < ids.length - 1) {
builder.append(",");
}
}
builder.append(")");
return builder.toString();
}
return null;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment