simonvt / schematic Goto Github PK
View Code? Open in Web Editor NEWAutomatically generate ContentProviders
Automatically generate ContentProviders
Hi @SimonVT!
This is not a proper issue, but a discussion. I wrote an Content provider like:
@ContentProvider(name = "Provider", database = Contract.class, authority = Provider.AUTHORITY)
public final class Provider {
public static final String AUTHORITY = "com.my.authority";
private static final Uri BASE = new Uri.Builder().scheme(SCHEME_CONTENT).authority(AUTHORITY).build();
@TableEndpoint(table = EQUIPMENTS)
public static final class Equipments {
@ContentUri(path = EQUIPMENTS, type = "vnd.android.cursor.dir/" + EQUIPMENTS, table = EQUIPMENTS)
public static final Uri CONTENT_URI = BASE.buildUpon().appendPath(EQUIPMENTS).build();
}
@TableEndpoint(table = OPERATIONS)
public static final class Operations {
@ContentUri(path = OPERATIONS, type = "vnd.android.cursor.dir/" + OPERATIONS)
public static final Uri CONTENT_URI = BASE.buildUpon().appendPath(OPERATIONS).build();
}
}
When the code is generated, I noticed that all @ContentUri
fields are grouped in top of Content provider, like:
public class Provider extends ContentProvider {
public static final String AUTHORITY = "com.my.authority";
private static final int CONTENT_URI = 0;
private static final int CONTENT_URI = 1;
// ...
}
I coded this way, because I believe that Provider.Operations.CONTENT_URI
is better than Provider.Operations.OPERATIONS
or Provider.Operations.OPERATIONS_CONTENT_URI
and so on.
Maybe, while generating code, the processor could rename the @ContentUri
fields to something like (e.g.) <@TableEndpoint class name>_CONTENT_URI
, without problem, because this name is internal to generated Content provider.
What do you think about it?
Hi,
Similar to the @NotifyX
annotations, a @NotifyBulkInsert
will be great so we could notify parent uris.
Thanks!
It would seem it is not possible to use the same interface for multiple tables in the same database.
@Table(JsonIdColumns.class) public static final String GITHUB_REPOSITORIES = "repositories";
@Table(JsonIdColumns.class) public static final String USER_SETTINGS = "userSettings";
Yields me an error:
Error:Execution failed for task ':app:_compileDebugJava'.
> java.lang.IllegalArgumentException: com.tehmou.rxbookapp.data.schematicProvider.JsonIdColumns
If I create a new interface for each table and extend the same base class it works. I would suggest either show a more meaningful error, or enable using the same column declarations for multiple tables.
I am new to schematic and I can't figure this one out just looking at the source code. How could I create an InexactContentUri such that I can get table elements using a 'selection' type like "LIKE ?" and the corresponding selection arguments?
...and thanks a lot for this great project.
The 0.6.0 version of Schematic seems to work fine, but it ignores the schematicOutPackage parameter and generates the classes in build.{buildtype}.{the.usual.application.package}.generated instead. Is this the intended behaviour? Regards, Jakub
How integrate schematic and sqlcipher?
I can run the app from android studio only if I do a rebuild first, because the simple deploy crashes:
java.lang.RuntimeException: Unable to get provider hu.bendaf.udacity.popularmovies.popularmoviesapp.data.generated.MovieProvider: java.lang.ClassNotFoundException: Didn't find class "hu.bendaf.udacity.popularmovies.popularmoviesapp.data.generated.MovieProvider" on path: DexPathList[[zip file "/data/app/hu.bendaf.udacity.popularmovies.popularmoviesapp-1/base.apk"],nativeLibraryDirectories=[/vendor/lib, /system/lib]]
Here is my app:
https://github.com/bendaf/PopularMoviesApp
I am using samsung galaxy s3 with API level 21.
Am I doing something wrong?
I found that in in @InexactContentUri, there is a join attribute but not sure how to use it. I would like to generate a content uri that joins two tables on t1.foreign_key_of_t2 = t2.primiary_key
WeatherTable INNER JOIN LocationTable
ON WeatherTable.LOC_KEY = LocationTable._id
and '_id' are in both tables so I have to write tableName.columnName
It seems like schematic requires a minSdkVersion
of 15. This is my current build.gradle
configuration:
android {
// ...
defaultConfig {
minSdkVersion 14
targetSdkVersion 19
// ...
}
}
With the above gradle configuration, I get the following build error:
Error:Execution failed for task ':app:processDebugManifest'.
> Manifest merger failed : uses-sdk:minSdkVersion 14 cannot be smaller than version 14 declared in library net.simonvt.schematic:schematic:0.5.1
14 cannot be smaller than 14? That makes no sense. So with useOldManifestMerger
set to true,
android {
// ...
useOldManifestMerger true
defaultConfig {
minSdkVersion 14
targetSdkVersion 19
// ...
}
}
I get a more reasonable error:
Error:Main manifest has <uses-sdk android:minSdkVersion='14'> but library uses minSdkVersion='15'
Error:Execution failed for task ':app:mergeDebugManifests'.
> Manifest merging failed. See console for more info.
Is there any way to configure schematic to use a minSdkVersion
of 14?
Could anyone confirm an example of setting conflict resolution?
public interface UsersColumns {
@DataType(INTEGER)
@PrimaryKey(onConflict = ConflictResolutionType.REPLACE)
String USER_ID = "user_id";
@DataType(TEXT)
@NotNull
String NAME = "name";
}
I guess it's a feature rather than a bug yet I feel it's quite odd.
I find that even without declaring @NotifyInsert
, @NotifyBulkInsert
, @NotifyUpdate
and @NotifyDelete
, the onLoadFinished (of a cursorLoader with query of certain URI) callback function still get invoked when insert, update and delete operations is performed to that URI.
I guess this is not a bug? It's just quite wired because supporting @NotifyInsert
, @NotifyBulkInsert
, @NotifyUpdate
and @NotifyDelete
somehow means that no notifying on data change without declaring these annotations.
I declare the URI with
public static class Quotes {
@ContentUri(
path = Path.QUOTES,
type = "vnd.android.cursor.dir/quote"
)
public static final Uri CONTENT_URI = buildUri(Path.QUOTES);
@InexactContentUri(
name = "QUOTE_ID",
path = Path.QUOTES + "/*",
type = "vnd.android.cursor.item/quote",
whereColumn = QuoteColumns.SYMBOL,
pathSegment = 1
)
public static Uri withSymbol(String symbol) {
return buildUri(Path.QUOTES, symbol);
}
}
and query the database by defining a cursorLoader
new CursorLoader(this, QuoteProvider.Quotes.CONTENT_URI,
projection,
selection,
selectionArg,
null);
and modify the database with
getContentResolver().delete(QuoteProvider.Quotes.withSymbol(symbol), null, null);
Then onLoadFinished gets called automatically without I declaring notifyDelete
First, thank you so much for this great project!
I am trying it on a new app and now came to a point where I ask myself whether it is possible to generate a ContentUri
with a GROUP BY
-statement.
I have a BLOB column in my database that I use it to store boolean values.
ContentValues
class accepts true/false as a direct parameter and stores them as 1 and 0 in the database. When I query normally, I have to like this WHERE PREFERRED=1
. When I use selectionArgs
and send new String[] {"1"}
it returns an empty Cursor
.
The same thing is happening to the below query. I sends "1" as the parameter using selectionsArgs
and the result is always empty.
@InexactContentUri(
name = "OPENWITH_PREFERRED",
path = OpenWithDatabase.OPENWITH + "/preferred/#",
type = "vnd.android.cursor.dir/openwith",
whereColumn = PREFERRED,
pathSegment = 2)
public static Uri preferred() {
return Uri.withAppendedPath(CONTENT_URI, "preferred/1");
}
At the end, I couldn't find any way to query boolean columns using @InexactContentUri
I hope I will be understood. I don't know if this is a bug or not. I just wanted you to know it.
Depending on the version number, do you think that it is possible to keep the state of the table and automatically determine the changes to the columns and tables?
If it is possible, maybe there can be a way to auto add new tables and new columns to databases. These 2 types of migrations should be pretty straightforward if that is possible.
Is there a way to use database from assets
As suggested in #63 we can add support for other table constraints.
I can do it. But I'd like to discuss some details regarding PrimaryKey
PrimaryKey
for column and on table level).PrimaryKey
annotation is specified for multiple columns. Something like this: "Consider to use PrimaryKey annotation on table level".It would be nice to hear pros and cons of Schematic, compared to existing projects, such as ProviGen and AnnotatedSQL.
Hi, @SimonVT .
I'm thinking about creating merge request with "column getter" functionality (see description below). Please tell me if it suitable for library or not.
Motivation: Instead of writing String note = cursor.getString(cursor.getColumnIndex(NoteColumns.NOTE));
just call String note = NotesGetter.noteString(cursor);
. It's more significant when you deal with nullable columns.
Couple details about suggested implementation:
getColumnIndexOrThrow
instead of getColumnIndex
. I think this approach is more robust because let identify problems earlier.null
for wrappers. Example of generated code. public static Integer getIdIntOrNull(Cursor cursor) {
int index = cursor.getColumnIndexOrThrow(NoteColumns.ID);
if (cursor.isNull(index)) {
return null;
} else {
return cursor.getInt(index);
}
}
public int getIdInt(Cursor cursor) {
return cursor.getInt(cursor.getColumnIndexOrThrow(NoteColumns.ID));
}
null
support despite @NotNull
annotation.Hello!
More than an issue, I am asking for an example here... I didn't see a similar one. So let's say I have 3 tables: Shows, Seasons and Episodes. The 3 tables have a show id (Seasons and Episodes have it as a foreign key). Also, Episode has a foreign key "season" pointing to the Season table.
I want to query the table Shows where Show.state = "state_a" and then do a join so I get:
Show.name
Season.number
Episode.number
Episode.title
I saw that the @ContentUri has "where" and also "join" but I haven't really been lucky using it...
Hope this question is ok. By the way, I saw this library announced in the Android Nanodegree by Udacity, congrats!
Hi @SimonVT, thank you for this useful lib!
Why the compiler does not support inheritance attributes of the interface? For example:
interface ModelColumns {
@PrimaryKey @AutoIncrement @DataType(DataType.Type.INTEGER) String _ID = "_id"
@DataType(DataType.Type.TEXT) String UUID = "uuid"
}
interface ListColumns extends ModelColumns {
@NotNull @DataType(DataType.Type.TEXT) String TITLE = "title"
}
Produce the SQL:
public static final String LISTS = "CREATE TABLE lists ("
+ ListColumns.TITLE + " TEXT NOT NULL)";
I know that this isn't an issue, but a feature that can save more time... :)
Currently I'm trying to set a @InexactContentUri where the whereColumn can be any of 2 columns in my table.
I would requiere the where clause to be:
WHERE whereColumn1 = pathSegment OR whereColumn2 = pathSegment
This seems to be impossible with the current setup because whereColumn are joined with an AND. Would be good to have an option to join them via an OR
Or alternatively make the where work without require the whereColumn parameter. I tried to use the where parameter but currently it doesn't allow the whereColumn clause to be empty. Also couldn't find a way on how the where clause could use the path segments.
Schematic is pretty awesome! It would be really cool if it would support specifying the "ON CONFLICT ..." policy for the "@unique"-annotated fields. Thanks for the awesomeness!
Really appreciate you making this lib available, it looks like a big time saver, but unfortunately I'm not having any luck getting up and running. The AndroidManifest.xml provider entry blows up with a cast error to the content provider class. I must be missing something - I have created the content provider definition, but I suspect the code generation is not happening because of something I've not done but cannot see what.
http://stackoverflow.com/questions/26120190/android-schematic-content-provider-library-configuration
Hi guys,
I want to build a Uri with two parameters using schematic:
public static Uri withMovieIdAndSeasonNumber(String movieId, String seasonNumber) {
return Uri.parse("content://" + AUTHORITY + "/show/" + movieId + "/season/" + seasonNumber);
So I need to implement the following SQL request with 2 where columns :
Select * from seasons where show_id = '31917' AND season_number = '7';
Is the following syntax correct ? It says "Attribue value must be constant" for the where clause.
@Where(path = "show/#/season/#")
public static String[] multipleWhere() {
return new String[] {
SeasonsTable.COLUMN_SHOW_ID,
SeasonsTable.COLUMN_SEASON_NUMBER
};
}
@InexactContentUri(
path = "show/#/season/#",
name = "SEASON_NUMBER",
type = "vnd.android.cursor.item/season",
whereColumn = multipleWhere(), // It says Error Attribute must be constant ?
defaultSort = SeasonsTable.COLUMN_SEASON_NUMBER + " DESC",
pathSegment = 1)
public static Uri withMovieIdAndSeasonNumber(String movieId, String seasonNumber) {
return Uri.parse("content://" + AUTHORITY + "/show/" + movieId + "/season/" + seasonNumber);
Any help much appreciated
Hi,
First off I want to thank you for creating this library. I think it's awesome. I had a few questions about it though.
Thank you,
David
Hello, have really enjoyed using your generator so far!
I'm setting up some test cases currently and have a couple of questions: what is the best way to obtain the database for testing use in an AndroidTestCase? Previously, when I wasn't using generated code, I would simply call my SomeDbHelper which extended the SQLiteOpenHelper. Is there a similar class being generated?
Thank you
L.
My android application contains some complex (normalized) database structure.
I didn't found any example which show case how one can use your library for such complex query.
Can you please provide/guide me an example for query like shown as below?
Ex:
SELECT * from Place
LEFT JOIN Itinerary
ON Itinerary.place_id = Place.place_id
AND Itinerary.trip_id='domtrip001';
I'm trying out the Schematic library and it is pretty cool! However, the most recent version of Schematic in Maven is the 0.5.3 (e.g. lacking the "@unique" annotation). Would it be possible to upgrade it? Many thanks.
Hi,
Thanks a lot for this lib, one of the best ContentProvider around here !
I used it for a small school project and noticed the bulkInsert
method is missing which is really useful to insert several rows at the same time, do you plan to add it?
Thanks!
Hi,
When I go here, I see the new releases, but I don't see the changelog. Please, could you edit the releases so we can see what's new in them without having to search the repository for a changelog file?
Hi @SimonVT,
I noticed @OnUpgrade
annotation, allowing to change schema. A bit more documentation of that could be useful.
Anyway, I didn't see anything to help to initialize database data. For example, suppose that I should put some initial data in tables. How can I made this? Maybe an @OnCreate
annotation could help.
What do you think?
Getting the following error when trying to run the sample. I've been using Eclipse w/o gradle this whole time so gradle is a tad new to me. I apologize beforehand if it's my lack of gradle skills resulting in the error.
java.lang.RuntimeException: Unable to get provider net.simonvt.schematic.sample.provider.NotesProvider: java.lang.ClassNotFoundException: Didn't find class "net.simonvt.schematic.sample.provider.NotesProvider" on path: DexPathList[[zip file "/data/app/net.simonvt.schematic.sample-2.apk"],nativeLibraryDirectories=[/data/app-lib/net.simonvt.schematic.sample-2, /system/lib]]
This uri always returns a failure in updating,
content://app.droidekas.contactsmanager.db.schematicProvider.ContactProvider/networkRequestStatuses/-50089794
,while all positive values work. I am not sure if this is a ContentProvider issue or Schematic related. Although it seems stupid ,I have tried by using positive values only and have no issues.
Can this be a problem?
Edit:
I debugged the code within generated/ContactProvider,
in @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)
,
MATCHER.match(Uri.parse(uri.toString().replace("-",""))) matches correctly while MATCHER.match(uri) fails,
Thank you for this project, it is excellent. Just a minor issue I had with table joins that might help others..
Notice the need to add a space " " in front of the JOIN keyword
@ContentUri( path = Path.SITE_PRICE_LAT_LNG,
type = "vnd.android.cursor.dir/site_price_lat_lng",
table = Path.SITE_PRICE,
join = " JOIN " + BrowserDatabase.FullSites.FULL_SITES + " ON " + BrowserDatabase.SitePrice.SITE_PRICE + "." + SitePriceColumn._ID + " = " + BrowserDatabase.FullSites.FULL_SITES + "." + FullSiteDetailsColumns._ID
)
Otherwise when generated this statement gets mangled
case SITEPRICELATLNG_SITE_PRICE_LAT_LNG: {
SelectionBuilder builder = getBuilder("SitePriceLatLng");
String join = " JOIN site_price ON site_price._id = full_sites._id";
String table = "site_price" + join;
Hope this makes sense
Thanks again
Some Table#getColumn
type thing.
Only problem is, what would @datatype(INTEGER) return? It can be a long, or an integer.
Could solve this by introducing a LONG data type (that's just an INTEGER behind the scenes or something).
First of all, this library is awesome. 😃
So upon running my current project in an emulator, I get the following stack trace:
Process: com.nucleartide.gourmet.app, PID: 1428
java.lang.RuntimeException: Unable to get provider com.nucleartide.gourmet.app.data.RecipeProvider: java.lang.ClassCastException: com.nucleartide.gourmet.app.data.RecipeProvider cannot be cast to android.content.ContentProvider
at android.app.ActivityThread.installProvider(ActivityThread.java:4793)
at android.app.ActivityThread.installContentProviders(ActivityThread.java:4385)
at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4325)
at android.app.ActivityThread.access$1500(ActivityThread.java:135)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1256)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5017)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.ClassCastException: com.nucleartide.gourmet.app.data.RecipeProvider cannot be cast to android.content.ContentProvider
at android.app.ActivityThread.installProvider(ActivityThread.java:4778)
at android.app.ActivityThread.installContentProviders(ActivityThread.java:4385)
at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4325)
at android.app.ActivityThread.access$1500(ActivityThread.java:135)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1256)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5017)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595)
at dalvik.system.NativeStart.main(Native Method)
Forgive me if I say something dumb. I think the problem is that the wrong class is being used, since a schematic ContentProvider doesn't extend android.content.ContentProvider before the annotation is applied.
@ContentProvider(...)
public final class RecipeProvider {
// ...
}
This is backed up by the fact that android-apt
is configured this way.
apt {
arguments {
schematicOutPackage 'com.nucleartide.gourmet.app.provider'
}
}
And the fact that the generated ContentProvider at app/build/source/apt/debug/provider/RecipeProvider
does extend android.content.ContentProvider.
public class RecipeProvider extends ContentProvider {
// ...
}
Am I doing something wrong? Thanks in advance.
Something like ContentValues cv = Values.for(NoteColumns.class).columnName(value).build();
Hi @SimonVT.
Props for this time-saving library. 👍
Just wanted to point out something small I came across and I didn't know where else to post it. 😁
When I put the database class in a folder different from the provider class, for example the database in database/MovieDatabase.java
and the provider in provider/MovieProvider.java
, that resulted in this error:
app/build/generated/source/apt/debug/com/joslittho/popmov/data/provider/generated/MoviesProvider.java:
35: error: cannot find symbol database = MoviesDatabase.getInstance(getContext());
^
The solution that worked for me was to keep provider and database files in the same directory.
Thanks.
All the best
Hi!
Today, I am adding a table to my Database I use with Schematic, and I'm metting SQL hassle again to properly add manually the new table in the @OnUpgrade
annotated method. I think a version
parameter on @Table
annotation, with would default to 0, representing the first version which included the table would be a nice way to tell Schematic to add itself the table in the onUpgrade(...)
android framework method, following the table contract which for now is only used to access the ContentProvider and when the database is first created.
Hi,
I'm wondering how we can make changes to our database (like add/remove columns to the tables, add additional tables, and etc.)
It doesn't seem to be as simple as bumping up the DATABASE_VERSION
number. Doing that seems to "upgrade" the database, but it doesn't make any changes to the actual database schema itself.
The github repo seems to be lacking documentation on this, and I couldn't find much on Google either. Can anyone help me out? The more I learn, I'm willing to contribute to make the documentation more solid.
Not sure if I just have overseen the functionallity. I have never seen a option to drop a table (to a.e. reset the autoincrement index).
As of the Android Gradle plugin version 2.2, all functionality that was previously provided by android-apt is now available in the Android plugin. This means that android-apt is officially obsolete ;)
Many libraries (like Butterknife) are already using annotationProcessor and if Schematic is used (which depends upon apt) with libraries which use annotationProcessor then this create issues for others that depends upon annotationProcessor.
A Migration would help
Thanks
It is quite often that we need to reset the data base instead of manually update it.
Currently the method annotated with @OnUpgrade
is unable to call onCreate
method from generated Provider (actually we can reference the generated class and call that onCreate
method but we will have some little issue with the compiler).
What I would like to do is something as follow:
@OnCreate public static void onCreateDatabaseComplete(Context context, SQLiteDatabase db) {
}
@OnUpgrade public static void onUpgrade(Context context, SQLiteDatabase db, int oldVersion,
int newVersion) {
db.execSQL("DROP TABLE IF EXISTS test");
// RECREATE database schema, or somehow call `onCreate` here
}
Is there any workaround for this?
Hi !
If you still support the library, could you add an @ForeignKey annotation ?
Thanks
Best regards
First of all thanks for this library, it has and is of great help.
I would greatly appreciate some sort of short changelog for each release, it would help to get an overview of what's changed when evaluating an upgrade.
Cheers!
I'm currently using schematic in combination with Retrofit (and Gson) and I thought the Column interface seemed like boilerplate we could generate using the variable names, or the SerializeName annotation used by Gson. Has any thought been given along this line? I'd be glad to take a further look if you think this is a decent idea, I'd greatly appreciate if you could point me in the right direction!
This lib is pretty cool . Can we also have an @unique annotation? Should be fine , yes ?
I wonder how to do this using schematic. I've been avoiding complicated queries and I tried to avoid this as much as I could but I have some use cases where I need it.
I do need some queries that have sub-queries that need non constant values (like executing a function that will return the current date).
If I try to do that with schematic, I'll get:
Attribute value must be constant.
This is easy to fix if that value should be in the outer query, so we can create an @InexactContentUri
and pass anything we want from our code, example:
MyProvider.MyTable.withTime(util.getCurrentTime());
That would work fine, but if I do need util.getCurrentTime()
inside a subquery, I can't do it. I am assuming this is a limitation of the Annotation model. So... Is there a way to do this using schematic? Is it possible to write the call in a fully raw mode way and generate the provider too?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.