GithubHelp home page GithubHelp logo

Comments (20)

Buggaboo avatar Buggaboo commented on May 12, 2024 1

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. select(cond)..groupBy(prop)..orderBy(prop) etc..

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 groupBy support yet. Although this can be implemented from dart.

from objectbox-dart.

Buggaboo avatar Buggaboo commented on May 12, 2024

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 query method as a factory that takes a closure that takes instances of Condition in the body. Also one can leverage the .. cascade operator, so there's no need to declare those types as part of a builder pattern. And boolean operator overloading for any / join (i.e. respectively ||, &&).

At some point in the future, we'll can leverage extension (a la Objc: category, swift: extension), to bolt on the properties to create conditions. Right now, I'm generating the EntityType properties, in a separate EntityType_ class (like java).

@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.

from objectbox-dart.

vaind avatar vaind commented on May 12, 2024

Factory method taking Condition is what Go does (not closure, directly a list of conditions). That's probably similar to what you had in mind, isn't it? Maybe it would make the code/usage simpler without the closure?

box.Query(Person_.age.greaterThan(18), Person_.name.startsWith("John"))

from objectbox-dart.

vaind avatar vaind commented on May 12, 2024

A few things to keep in mind:

  • consider building queries an expensive operation, the idea is they should be built once and reusable (just changing parameter values)
  • there are links (over relation fields) - swift and go take slightly different approaches, with Go creating a condition and passing it to the query and swift chaining the link on the query object (therefore requiring an explicit build() call which Go doesn't need)

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

from objectbox-dart.

vaind avatar vaind commented on May 12, 2024

from objectbox-dart.

Buggaboo avatar Buggaboo commented on May 12, 2024

We can't use varargs or reuse method names, that's why I initially thought of passing a closure.
For example:

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.

from objectbox-dart.

vaind avatar vaind commented on May 12, 2024

Oh, no variadic functions in dart? What about taking a list then? Still less cumbersome than a closure

from objectbox-dart.

vaind avatar vaind commented on May 12, 2024

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

from objectbox-dart.

vaind avatar vaind commented on May 12, 2024

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 Condition interface, i.e. something produced by Person_.age.greaterThan(18) or by an operator overload (a combination of two conditions) - Person_.age.greaterThan(18) && Person_.name.startsWith("A")

from objectbox-dart.

Buggaboo avatar Buggaboo commented on May 12, 2024

I have something working, it might leak or explode on your machine. I'm not ready to merge yet, but count already works.

This design allows for very complex Condition trees using and / or.
It would be nice if the user wouldn't need to manually close a query.

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 box.queryAll and box.queryAny function, e.g.:

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();

from objectbox-dart.

vaind avatar vaind commented on May 12, 2024

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 - I hope it gets merged soon. It's merged into dev now.

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.

from objectbox-dart.

Buggaboo avatar Buggaboo commented on May 12, 2024

I'll do a PR after I implement findFirst / find / findIds. I quickly implemented findFirst and find by (ab)using Box<T>.getMany.

I plan to expose new OBXFlatbuffersManager<T> in a certain Box<T> to the queries, to reuse for unmarshalling the buffer from find. Instead of passing the whole box like I do right now.

I haven't started on orderBy yet.

from objectbox-dart.

vaind avatar vaind commented on May 12, 2024

I plan to expose new OBXFlatbuffersManager<T> in a certain Box<T> to the queries, to reuse for unmarshalling the buffer from find. Instead of passing the whole box like I do right now.

Yes, makes sense for queries to have access to their entity's box. Similar is done in Go.

I haven't started on orderBy yet.

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.

from objectbox-dart.

GregorySech avatar GregorySech commented on May 12, 2024

Hi,
I'm not sure if this is still a matter of discussion however I wanted to share a couple of Dart projects with built-in ORMs.
I guess that a major part of the objective here is having an API similar to the other languages SDKs but maybe some inspiration can be drawn from these:

Edit:
Maybe the aqueduct one is a little out of scope as it isn't compatible with Flutter.

from objectbox-dart.

GregorySech avatar GregorySech commented on May 12, 2024

Would be really nice, about aggregators I guess it's fine.
For what is worth I really dig the idea of using operator overloading to logically join the Conditions.

from objectbox-dart.

vaind avatar vaind commented on May 12, 2024

@GregorySech

I'm not sure if this is still a matter of discussion however I wanted to share a couple of Dart projects with built-in ORMs.
I guess that a major part of the objective here is having an API similar to the other languages SDKs but maybe some inspiration can be drawn from these:

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.

from objectbox-dart.

vaind avatar vaind commented on May 12, 2024

@Buggaboo

We don't really have groupBy support yet. Although this can be implemented from dart.

FYI, aggregators are (to some extent) supported by objectbox-c = Property-Query OBX_query_prop - that would end up as a new issue I guess, certainly not in scope of this one.

Since objectbox is not a SQL DB, I don't feel that we have to stick to that syntactic tradition, e.g. select(cond)..groupBy(prop)..orderBy(prop) etc..

Certainly - while there are similarities, ObjectBox doesn't even want to look/work like SQL.

from objectbox-dart.

vaind avatar vaind commented on May 12, 2024

Thank you @Buggaboo for tackling this. It ended up to be quite a big PR 👍

from objectbox-dart.

Buggaboo avatar Buggaboo commented on May 12, 2024

Well, we did it together more or less. Now we have proper ffi Structs etc., and other fancy stuff. I learned a lot.

from objectbox-dart.

greenrobot avatar greenrobot commented on May 12, 2024

Awesome! 👍

from objectbox-dart.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.