-
Notifications
You must be signed in to change notification settings - Fork 88
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
Minimally useful query syntax #132
Minimally useful query syntax #132
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A couple inline comments.
My only concern here is the ability to eventually insert JOINs to handle associations along with the query syntax.
Have we looked at Lucky's query builder to see if it could be compatible and if it does what is needed?
src/query/builder.cr
Outdated
self | ||
end | ||
|
||
def _build_order |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are these underscore methods meant to indicate internal use? If so, make them private.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes and no. They can't be private because they're called by the Query::Compiled
class. I think this is evidence of an architectural mis-step in this design, but I can't quite see what the correction would be yet.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't really change things, but I like it a little more:
def order
set_default_order if @order.none?
build_order
end
private def build_order
@order.map { |expression| "#{expression[:field]} #{expression[:direction]}" }.join(", ")
end
private def set_default_order
@order = [{ field: T.primary_name, direction: "ASC" }]
end
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
protected
might be what you are looking for
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, technically, _build_order
is returning an order clause, right? so:
def order
- def order_clause : String
private def build_order
-> private def build_order_clause : String
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@eliasjpr - There isn't any inheritance, an instance of this class is used in class he mentioned.
Some of these classes could potentially be made into module mixins, just going off names:
Query
- noun, class
A query you can build, compile, and run - those could be modules that the Query
mixes in
src/query/runner.cr
Outdated
def initialize(@query : Compiled(T)) | ||
end | ||
|
||
def log(*args) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will need to hook into a logger eventually, right? So it doesn't log in production.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yep, it's just a stub for now
@marksiemers I haven't done anything thing in here yet with it, but I'm trying to keep joins in mind for sure. Thanks for looking! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good start. Some comments.
src/query/builder.cr
Outdated
self | ||
end | ||
|
||
def order(field : Symbol) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what about using a tuple instead order(updated_at: :asc)
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The other overload does exactly that. This method is meant to be called: .order(:id)
and assumes :asc
.
src/query/builder.cr
Outdated
self | ||
end | ||
|
||
def _build_order |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
protected
might be what you are looking for
src/query/builder.cr
Outdated
# | ||
# - Model.where(field: value).or( Model.where(field3: value3) ) | ||
# or | ||
# - Model.where(field: value).or { whehre(field3: value3) } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why no Model.where(field: value).or(field3: value3)
There are a couple tests now, but they're written with some project specific requires where I'm using this query language in my amber project. Changing the require statements will be required to get the suite to pass. |
Fixes #158 |
@robacarp what is the status on this? I really like the work done and think the foundation provides more additional features down the road. Let me know if I can help work on some of it. |
@drujensen Thanks for looking. It's status is "pending". I'd like to move the tests into place for the granite repo, so that it can pass specs, and then it can be merged in relatively short order so others can contribute. There are some big components missing, but I think it's the beginnings of a usable foundation. So long as it continues to be opt-in, I'd be fine having it in master. At some point when it's more stable, it can be included by default. Is that a sane way to open the doors for more collaboration? |
@robacarp yeah, we can include this in master as long as it doesn't break the existing stuff and then add to it until its full featured. We can keep it as an undocumented until we feel comfortable its ready for prime time. I think this is a great start! If we do document it, let's mark it as experimental because more than likely going to change over time as we iterate over it. WDYT? |
Agreed |
@drujensen @eliasjpr I've moved tests into the right place to run them, so I think this is ready for a merge so others can start collaborating on it. |
@faustinoaq good question, no. None of this takes effect in a granite model without explicitly including it, like this: class MyModel < Granite::ORM::Base
include Granite::Query::BuilderMethods
end It does share some of the same functionality, which I hope will merge down the line, but it's independent. |
end | ||
|
||
def log(*stuff) | ||
puts |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we use granite logger?
Hi, Is this documented in Granite's README? 😅 |
@faustinoaq no, it's not. I'm not sure it's ready for the readme yet. I do want to ping @noahlh that this code exists though, because I think it might be relevant to the custom query work he's doing. |
@robacarp thank you for the ping! I have to apologize - I totally missed this PR when I started diving into my |
@noahlh no apology necessary. This is pretty minimal, but I think it'd benefit from the way you're thinking about things as well. Happy to hop on a pairing session to see how we can make it all work together |
There's been some chatter about building a query syntax for granite. I've been tinkering with this, added to my Amber project directly. I've included it here as a granite extension for simplicity.
Goals:
Current status
This works:
Model.where(field: "value").count
Model.where(field: "value").first(n) / .first / .any?
Model.where(field: "value").order(field: :desc)
Model.where(field: "value").delete
Model.where(...).raw_sql
Currently there is only a query builder for Postgres, but all query generation logic is contained with Assembler::Postgres, so adding a Mysql and Sqlite compliant version shouldn't be too difficult. 🍌
I'd really like to work together on this. Granite has a great history of working together over time! If the current code is a viable starting point, let's get it in and everyone can contribute.
🥑