Skip to content
This repository has been archived by the owner on Mar 25, 2020. It is now read-only.

ContentQuery

Ricky Tobing edited this page Aug 26, 2013 · 13 revisions

ContentQuery is an extension library that allows you write DbQuery-style query to ContentProvider.

NOTE ContentQuery depends on DbQuery. This wiki is written with assumption that you are familiar with DbQuery library. Please see https://github.com/bingzer/DbQuery/wiki for more information

Uri uri = ...
IResolver resolver = ContentQuery.resolve(uri, getContext());

Cursor cursor = resolver.select("name = ? or display like ?", "John", "John%")
                        .columns("_id", "name")
                        .orderBy("name desc", "_id")
                        .query();

What is a IResolver?

It is a wrapper around ContextResolver that allows you to write DbQuery-style query. There are two types of resolvers: IResolver and IStrictResolver. Basically, IStrictResolver offers a strict and less functionalities than the normal IResolver.

To get resolver objects there are several options:

  • IStrictResolver
String uriString = ...
IStrictResolver strictResolver = ContentQuery.strictlyResolve(uriString, getContext());
// or
Uri uri = ...
IStrictResolver strictResolver = ContentQuery.strictlyResolve(uri, getContext());
  • IResolver
String uriString = ...
IResolver resolver = ContentQuery.resolve(uriString, getContext());
// or
Uri uri = ...
IResolver resolver = ContentQuery.resolve(uri, getContext());

IResolver vs IStrictResolver

  • IStrictResolver provides a strict implementation. This type of resolver restrict the LIMIT clause inside a query. So pagination or SELECT TOP is not implemented
  • IResolver provides a lenient implementation. This type of resolver allows PAGING and SELECT TOP implementation

The rule of thumb is to always refer to your ContentProvider's documentation. If you're not familiar with the ContentProvider, you should NEVER use IResolver because your query may break the ContentProvider implementation.

ContentConfig

ContentConfig is used to configure your resolver. These are some configurations that are optionally needed to query from Android built-in providers:

IStrictResolver resolver = ContentQuery.strictlyResolve(UserDictionary.Words.CONTENT_URI, getContext());
// sets the 'Id' naming convention. Default is '_id'
resolver.getConfig().setIdNamingConvention("_id");
// sets the default projections
resolver.getConfig().setDefaultProjections("_id", "word");
// sets the default authority (used in 'bulk-insert')
resolver.getConfig().setDefaultAuthority(UserDictionary.AUTHORITY);

Important Always configure before doing query

  • Most of the ContentProvider uses _id (lowercase) as their id. By default, ContentQuery uses _id as Id. Again, consult your ContentProvider's documentation.
  • ContentConfig.setDefaultProjections() determines the default projections (columns) to return if otherwise being overriden in Select.columns() method. The default value for this ContentConfig.getIdNamingConvention(). If null is specified, the value will also be ContentConfig.getIdNamingConvention()
  • ContentConfig.setDefaultAuthority() provides the authority String when doing bulk-insert.

#IResolver.count()

  • IResolver.count() returns the total records.
  • IResolver.count(String condition) returns the total records that matches the condition
  • IResolver.count(String whereClause, Object... args) returns the total records that matches the whereClause. This is more preferred way then calling count(condition).

#IResolver.has()

  • IResolver.has(int id) returns true if a record with the same id exists; false if otherwise
  • IResolver.has(String condition) returns true if a record or more exists that matches the condition; false if otherwise
  • IResolver.has(String whereClause, Object... args) returns true if a record or more exists that matches the specified whereClause; false if otherwise

SELECT Statement

As found in DbQuery implementation, SELECT is implemented the same way:

IStrictResolver resolver = ...
resolver.getConfig().setDefaultProjections("_id", "word");
// select "_id" and "word" and order by word DESCENDING
Cursor cursor = resolver.select()
                        .orderBy("word DESC")
                        .query();
  • Paging is available only when you're using IResolver. Paging is made possible by appending LIMIT X OFFSET Y argument to OrderBy clause. Again, you should always consult your ContentProvider documentation before doing Paging as it may break the provider's implementation.
IResolver resolver = ...
resolver.getConfig().setDefaultProjections("_id", "word");
// select "_id" and "word" and order by word DESCENDING
IQuery.Paging paging = resolver.select()
                        .orderBy("word DESC")
                        .paging(10);            // ten in a row
...
Cursor cursor = paging.query();
assertTrue(paging.getPageNumber() == 0);        // first page
...
cursor = paging.next().query();
assertTrue(paging.getPageNumber() == 1);        // second page

INSERT Operation

Many options to do an INSERT operations:

  • Using ContentValues As always, ContentValues is a first-citizen in ContentQuery
IStrictResolver resolver = ...
// or
IResolver resolver = ...

ContentValues values = new ContentValues();
values.put("word", "OLA");

int newId = resolver.insert(values);
  • Others:
IStrictResolver resolver = ...
// or
IResolver resolver = ...

int newId = resolver.insert("word")
                    .val("ABCDEFG")
                    .query();
// or
int newId = resolver.insert(
                        new String[]{"word"}, 
                        new Object[]{"ABCDEFG"})
                     .query();
  • How do I get the Uri? Insert object stores the Uri as string in the toString() method.
IStrictResolver resolver = ...
// or
IResolver resolver = ...

IQuery.Insert insert = resolver.insert("word")
                               .val("ABCDEFG");
int newId = insert.query();

String uriString = insert.toString();
Uri uri = Uri.parse(uriString);

UPDATE Operation

To do an UPDATE operation:

  • Using ContentValues.
IStrictResolver resolver = ...
// or
IResolver resolver = ...


ContentValues values = new ContentValues();
values.put("word", "Baloteli-Updated");

int id = ...
int numUpdated = resolver.update(values, id)
                         .query();
// or
int numUpdated = resolver.update(values, "word = ?", "Baloteli")
                         .query();
  • Others:
IStrictResolver resolver = ...
// or
IResolver resolver = ...

int id = ...
int numUpdated = resolver.update(
                             new String[]{"word"}, 
                             new Object[]{"Baloteli-Updated"}, 
                             id);
// or
int numUpdated = resolver.update(
                             new String[]{"word"}, 
                             new Object[]{"Baloteli-Updated"},
                             "word like ?",
                             "Baloteli");

DELETE Operation

To perform delete:

IStrictResolver resolver = ...
// or
IResolver resolver = ...

// By Id
int id = ...
int numDeleted = resolver.delete(id)
                         .query();

// By Condition (maybe bulk-delete)
// bulk-delete any word that ends with 'ed'
int numDeleted = resolver.delete("word like ?", "%ed")
                         .query();

IEntity and IEntityList

IEntity and IEntityList are both supported in ContentQuery:

public class Word implements IEntity{
    ...
}

...

public class WordList extends LinkedList<Word> implements IEntityList<Word>{

    @Override
    public List<Word> getEntityList() {
        return this;
    }

    @Override
    public Word newEntity() {
        return new Word();
    }
}
IStrictResolver resolver = ...
// or
IResolver resolver = ...

WordList wordList = new WordList();
resolver.select().query(wordList);

assertTrue(wordList.size() > 0); // populated!
Clone this wiki locally