emilsjolander / sprinkles Goto Github PK
View Code? Open in Web Editor NEWSprinkles is a boiler-plate-reduction-library for dealing with databases in android applications
License: Apache License 2.0
Sprinkles is a boiler-plate-reduction-library for dealing with databases in android applications
License: Apache License 2.0
Hi!
I am writing a few tests for code that does business logic and triggers asynchronous db operations through sprinkles. My tests are basically failing when they expect certain data to be present in db, but the data is missing due to the async write not being completed yet. Therefore, for testing purposes, it seems that I need a way to wait for the async jobs to be finished before I do my assertions.
I have taken a quick look at Sprinkles but there doesn't seem to be a waiting mechanism, is that correct? Does Android provide a generic way to wait for all ongoing AsyncTasks to be completed? Otherwise, any tips on how to tackle this problem?
Thanks!
A better sample application should be created. I would still like it to use Notes and Tags as it shows how to use sprinkles with many to many relationships.
I would love to be able to hook into the callback in Model.save()
in order to tell the underlying content provider to start a sync adapter. For example the change might look like...
Sprinkles.sInstance.mContext.getContentResolver()
.notifyChange(Utils.getNotificationUri(Model.this.getClass()), null, true);
The extra true
param on the end would allow for using a SyncAdapter alongside Sprinkles.
I would be happy to implement this I'm just curious if @emilsjolander has any input on this.
Thanks
Hi,
Recently I've discovered that all annotations were removed from model classes in obfuscated code.
Crash: java.lang.RuntimeException: Unable to create application com.example.App: se.emilsjolander.sprinkles.exceptions.NoPrimaryKeysException: Every model must have at least one primary key!
So I think sprinkles needs proper proguard config.
All queries should return a list subclass (ModelList??) that has methods like deleteAll()
and saveAll()
Hello world!
I'm seeing some strange issues with Sprinkles when using it in my nested Fragments (in a FragmentStatePagerAdapter
that I pass getChildFragmentManager()
into).
Consider the following code in onViewCreated
:
DetailedStatsDAO detailedStatsDAO = Query.one(
DetailedStatsDAO.class,
"SELECT * " +
"FROM " + DetailedStatsDAO.TABLE_NAME + " " +
"WHERE soldierId = ? AND platformId = ? AND version = ?",
arguments.getString(Keys.Soldier.ID, ""),
arguments.getInt(Keys.Soldier.PLATFORM, 0),
BuildConfig.VERSION_CODE
).get();
Log.d("HelloSprinkles", "[onViewCreated] detailedStatsDAO => " + detailedStatsDAO);
sendDataToListView(view, detailedStatsDAO.getDetailedStats().getItems());
showLoadingState(false);
This populates the ListView
as expected to, as statsDAO
is an instance of DetailedStatsDao
:
D/HelloSprinkles﹕ [onViewCreated] detailedStatsDAO => DetailedStatsDAO@43c73408
However, consider the same query and handling of result, but using getAsync()
instead:
Query.one(
DetailedStatsDAO.class,
"SELECT * " +
"FROM " + DetailedStatsDAO.TABLE_NAME + " " +
"WHERE soldierId = ? AND platformId = ? AND version = ?",
arguments.getString(Keys.Soldier.ID, ""),
arguments.getInt(Keys.Soldier.PLATFORM, 0),
BuildConfig.VERSION_CODE
).getAsync(
getLoaderManager(),
new OneQuery.ResultHandler<DetailedStatsDAO>() {
@Override
public boolean handleResult(DetailedStatsDAO detailedStatsDAO) {
Log.d("HelloWorld", "[getAsync] detailedStatsDAO => " + detailedStatsDAO);
if (detailedStatsDAO == null) {
return true;
}
sendDataToListView(view, detailedStatsDAO.getDetailedStats().getItems());
showLoadingState(false);
return true;
}
}
);
This instead gives me a null
value, for some non-apparent reason:
D/HelloSprinkles﹕ [getAsync] detailedStatsDAO => null
If I then swipe to the fragment in question, it gets passed an OK instance upon the fragment sliding into view:
D/HelloSprinkles﹕ [getAsync] detailedStatsDAO => DetailedStatsDAO@449d0808
...and, as an added "whaaaaa...t" bonus, passing getFragmentManager()
instead of getChildFragmentManager()
in the parent fragment seems to get me the correct results using getAsync
:
D/HelloSprinkles﹕ [getAsync] detailedStatsDAO => DetailedStatsDAO@42d58fd8
Any thoughts? I'm not sure I fully understand why things are going down the way they are, as I believe getAsync
should be returning the same results as get()
does.
Thanks :-)
OK. I'll try my best to describe this correctly. Right now, I am not sure if I am doing something wrong or if there is a bug in the async callback.
I have a scenario where I check for the existence of a certain item in the DB before I save it and hence I have a Query.One().getAsync() call. The callback given to the getAsync() part is returning false and yet it gets called again when I actually do save the item if it doesn't exist in the database. Moreover, since I save to the DB using saveAsync(), Sprinkles seems to call the callback anyway even when the record has not yet been saved and, thereby resulting in two records in the DB for a single save.
I guess a simple code sample to illustrate would be clearer:
private OneQuery.ResultHandler<Example> onExampleLoaded = new OneQuery.ResultHandler<Example>() {
@Override
public boolean handleResult (Example example) {
if (example == null) {
String something = "hello";
Example newExample = new Example(something);
newExample.saveAsync(new Model.OnSavedCallback() {
@Override
public void onSaved () {
Log.i(TAG, "Saved"); //this executes twice
}
});
}
//don't want to be notified of further changes
return false;
}
};
This is in no way needed and just requires possibly unnecessary null checks
Support for raw sql execution. Something a long the lines of Sprinkles.exec(String sql, Object[] args)
and Sprinkles.execAsync(String sql, Object[] args)
I would like to use Sprinkles with an existing database. Right now, the database name is hardcoded in DbOpenHelper
. It would be great to be able to open a database with another name bundled in the App.
Upload an artifact to maven central
Hey there - just checking out your neat little library. Right now your migrations are controlled entirely by the size and order of the Sprinkles.mMigrations list, which is determined by the code that creates them. Although your README makes clear that you shouldn't change a migration after it's in production, you should maybe also point out that you should a) never change the order of migrations in your code, and b) only add new migrations at the end?
When doing migration.createTable()
and then adding a column with migration.addColumn()
it fails on new installs.
There are two solutions. We could automatically track changes of models and migrate when necessary, this would probably be hard to integrate with custom migrations in a predictable way which would be the downside.
The other solution would be to drop auto migrating of models and the user would need to manually migrate all columns. This would however cause the need for bigger changes as annotations currently made on columns would be unnecessary as those constraints should be added on the migration (which might be better than having to annotate properties?).
Support deleting multiple columns in one statement with an api looking something like this: Delete.all(Class<? extends Model> clazz, String sql, Object[] args)
Hi!
It would be very useful to have:
void saveAsync(Transaction t);
void saveAsync(Transaction t, OnSavedCallback callback);
Same goes for deletes.
Do you have any plans for implementing this?
Thanks and have a good day!
Javadoc for all methods. As well as more normal comments
Can you lower this to, say, 8? I can pull down the sources and modify it myself and do a local build but I'd like to avoid that, that is, if Sprinkles would even work at that level.
How do I get the results of Select count(*) from table?
Model.save
retrieves all ContentValues
before invoking beforeCreate()
which breaks fields that are not nullable but are initialized in beforeCreate()
. An example of this can be seen in the sample where a Note cannot be saved because of a NullPointerException
thrown by the DateSerializer
for the field createdAt
.
If we use the @unique annotation in different fields of a class, it will create a unique constraint per field. In some situations, it would be useful to be able to create unique constraint including more than one column.
Actually if i need all element i need to do
Query.many(Shipment.class, "select * from Shipment")
it would be better if it was
Query.many(Shipment.class)
Is sprinkles able to search by date?
Updating the sample app:
Query.many(Note.class, "select Notes.*, " +
"(select count(*) from NoteTagLinks where NoteTagLinks.note_id = Notes.id) as tag_count " +
"from Notes where created_at = ?", new Date());
This never returns any entries.
In one of the earlier versions of sprinkles, the Migration
class had a createTable()
method that seemed to make it much easier to manage the create statements. Is there anything similar in the current 1.3.1 version that would prevent me from having to craft my own CREATE statement?
sprinkles looks nice.
I really eager to switch to sprinkles.
But i need two feature : LazyLoad,Entity Cache.
Are there any way to support LazyLoad like this ?:
public class Parent{
private int id;
@OneToMany(manyColumn = "parentId")
private OneToManyLazyLoader<Parent ,Child> children;
/..../
}
public class Child{
private int id;
private String text;
@manytoone(column = "parentId")
private Parent parent;
/..../
}
It seems that you forgot to do a git add for these new annotations.
The readme says "Sprinkles actively supports version 2.3 of Android and above but it should work on older versions as well"
But the library has minSdkVersion=10 in the manifest. Is this a bug or is the minSdk 10?
The current README describes the functionality in the last commits (as the new migration system) but there is no release containing these changes, which makes it impossible for users to use via gradle.
Should we still show the old documentation until the new version is ready to be released? Or are we ready to do a release with this?
I had made and released an app with the old version of sprinkles(before you changed the migration model). Now we are releasing an update for the app .For this update,we are making lots changes to the structure and behaviour of the app database . I want to implement the following behaviour using sprinkles.
For my existing users, rather than doing any form of migration, I want to sprinkles to clear/delete the old database and recreate it. In other words, for my existing and new users, the application should behave the same(whether a previous version of db exists or not). Is there a build-in way to force-upgrade the db? Appreciate your help.
Is there any chance though that you could remove the styles.xml and the app_name definition in strings.xml, as it is messing with the layout previews in Android Studio?
How to add an index to a table?
Currently if you save a list of 100 Note.class in a transactions then 100 notification of content changed will be triggered when the transaction is commited.
I just wanted to update to version 1.2.1 but gradle fails because it couldn't find se.emilsjolander:sprinkles:1.2.1
.
Spinkles needs a logo along the lines of the current one but much prettier.
Hey @emilsjolander I love this library! I want to see if there is something I can do to help it progress. I am thinking of 2 main things.
@Table("Notes")
public class Note extends Model {
@AutoIncrementPrimaryKey
@Column("id")
private long id;
@Column("title")
public String title;
@Column("body")
public String body;
// suggested model relationships automatically generates UserId into this table for future lookup
@BelongsTo("User")
public User user;
// suggested model relationship
@HasMany("Tags")
public List<Tag> tags;
public long getId() {
return id;
}
}
// this would execute "SELECT * FROM Notes";
List<Note> notes = Notes.findAll();
// this would execute "SELECT * FROM Notes WHERE id = 1"
Note notes = Notes.find(1);
I have read the documentation but I am a little confused about how to clear the current date in the table. Currently I am doing this
ModelList person=ModelList.from(Query.all(Person.class).get())
person.deleteAll()
Is this the best way?
Using @PrimaryKey annotation in multiple fields of a class will create a composite primary key, but is there any way to create foreign key to point to that composite primary key?
As far as I know, we can only add a @foreignkey annotation to a specific field, which will only point to a part of the composite primary key, and therefore, fail.
Another alternative would be to, instead of creating a composite primary key, use @AutoIncrementPrimaryKey and add a multiple column unique constraint to the columns that were included in the composite primary key.
Unfortunately, I don't see a way to do that either. I opened an issue here:
#55
For now, what would be the best way to ensure for a table that the combination of two columns is unique?
Could I add that constraint manually in the table (using migration.addRawStatement?)?
Thanks a lot for your work, I am enjoying the library so far! :)
EDIT:
It seems that constraints cannot be added after table creation with sqlite:
http://stackoverflow.com/questions/1884818/how-do-i-add-a-foreign-key-to-an-existing-sqlite-3-6-21-table
Support the result of a query to have any arbitrary columns. My first though it to create a special class similar to ContentValues
but read only which will be past in as a model to the query methods.
Support updating multiple columns in one statement.
How can I make a query with the IN statement?
I have a case where i need to delete all the rows that have a specific value for a column. Is this possible. i see that Query.one/Query.many does execute raw SQL statements but it is expecting a model as a result. These things need just a count of affected rows.
Can you provide some more insight into this? How do you handle things like this?
Nice to see this project,
8tory had also implemented CursorList for ActiveAndroid before known this project. I would like to share these repositories to you, hope helpful:
Started on in pull request #25
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.