-
Notifications
You must be signed in to change notification settings - Fork 133
Basic Query (Builder) support #5
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
I started by wrapping the C functions, I'll share a branch soon. With regard to designing the interface, I'm thinking of passing a closure to the Store#query method, to produce a QueryBuilder object like swift. I think another way to do it idiomatically in dart is by declaring this At some point in the future, we'll can leverage @Entity class Person { @Id... }
final store = Store([...]);
final box = Box<Person>(store);
final query = box.query(() {
Person_.age.isNotNull()
..greaterThan(18); // equivalent to: && Person_.age > 18
}).build();
var p = query.findFirst(); Something like this. |
Factory method taking
|
A few things to keep in mind:
In any case, having a look at the query-builder implementation in go/swift may help you clear some things up. https://github.com/objectbox/objectbox-go/blob/master/objectbox/querybuilder.go |
We can't use varargs or reuse method names, that's why I initially thought of passing a closure. QueryBuilder Query(Condition... c) Nor this will work: QueryBuilder Query(Condition c1) { ... }
QueryBuilder Query(Condition c1, ..., Condition cn) { ... } We can do optional positional arguments though of constant size n, but I doubt that's gonna be pretty. |
Oh, no variadic functions in dart? What about taking a list then? Still less cumbersome than a closure |
And there's a "solution" for variadic functions as well actually: http://yuasakusa.github.io/dart/2014/01/23/dart-variadic.html It would be interesting to see the performance hit when compared to passing a list |
Actually, looking back at your original comment @Buggaboo, I quite like the idea of operator overloading. However, is it really necessary for Query to take a closure? What about taking a |
I have something working, it might leak or explode on your machine. I'm not ready to merge yet, but This design allows for very complex Also I'm not very sure of the type mapping I have right now: {
"dart" : "objectbox-c"
"int" : "Int64", // this could be Int32 instead, or even a c-byte (aka Uint8), dart<2.0 used to be arbitrary precision
"bool" : "Uint8",
} I added a final text = TestEntity_.text;
final anyGroup = <QueryCondition>[text.equal("meh"), text.equal("bleh")];
final queryAny = box.queryAny(anyGroup).build();
// equivalent to
box.query(text == "meh" | text == "bleh").build();
// equivalent to
box.query(text.equal("meh").or(text.equal("bleh"))).build(); |
I've taken first a look at the code and it looks good 👍 I especially like the operator overloads. There are a few things that could be updated with the changes introduced by #25 - Also, as you mentioned, it seems like #11 is a prerequisite of queries supporting all types. However, it doesn't mean we can't finish the rest first and maybe even merge it in. Do you mind creating a PR? It's fine if the code is unfinished but at least some parts could be clarified already. |
I'll do a PR after I implement I plan to expose I haven't started on |
Yes, makes sense for queries to have access to their entity's box. Similar is done in Go.
Order, offset, limit, params, etc. are not necessary for the first step. Let's limit the scope of this issue to "Basic query support" so the PR would be more manageable if you don't mind. |
Hi,
Edit: |
Thanks, the stream and futures look nice; there are async stuff on the objectbox-c project, that can be implemented to support async queries. The syntax is somewhat constrained by how objects/methods are defined in the objectbox-c project. There should be a new ticket for syntax-sugar related wish-list. Since objectbox is not a SQL DB, I don't feel that we have to stick to that syntactic tradition, e.g. I can imagine something like this: // box = Box<S> bla
final builder = box.query(S_.text == 'meh');
final firstFuture = builder.firstFuture(); // Future<S>
final listFuture = builder.future(); // Future<List<S>>
final generator = builder.generator(); // Iterator<S> Function();
final stream = builder.stream(); // Stream<List<S>>
// Stream<S> singleStream = builder.streamSingle(); // is probably achievable thru a StreamTransform.
try {
await print(firstFuture.toString());
await for(list in listFuture) {
print (list.map((s) => s.toString()).toList().join(", "));
}
print (generator()); // yields s0
print (generator()); // yields s1 after s0
print (generator()); // yields s2 after s1
await print(stream.first);
stream.listen((list) => print (list.map((s) => s.toString()).toList().join(", ")));
} catch (err) {
print('Caught error: $err');
} We don't really have |
Would be really nice, about aggregators I guess it's fine. |
Thanks, it's pretty similar to what we do in other languages as well but when there's a specific functionality that needs to be done differently, it's always nice to have a fairly "standardized" interface - that's where it makes much sense to look at other solutions - if it makes sense to provide familiar experience to developers. |
FYI, aggregators are (to some extent) supported by objectbox-c = Property-Query
Certainly - while there are similarities, ObjectBox doesn't even want to look/work like SQL. |
Thank you @Buggaboo for tackling this. It ended up to be quite a big PR 👍 |
Well, we did it together more or less. Now we have proper ffi Structs etc., and other fancy stuff. I learned a lot. |
Awesome! 👍 |
Goal: minimal solution including a query builder and a reusable query object. For reference, please check the Java query API.
The text was updated successfully, but these errors were encountered: