-
Notifications
You must be signed in to change notification settings - Fork 87
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
added query macro, tests, and docs #215
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.
Good start, I like the idea of supporting a viewmodel. I wonder if it should be a subclass of Base instead of a dedicated base class itself?
@@ -0,0 +1,21 @@ | |||
module Granite::Select | |||
struct Container |
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.
Could this be called a fieldset?
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.
It's not so much a set of fields as it is a (loose) container for the query (or SELECT) statement. Granite::Query
is used in your new query builder, so I tried to capture this as simply as possible. I don't love Granite::Select::Container
though. Open to ideas.
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.
Sure Container
is a little vague, but is it going to show up in an Amber devs code? If not, I don't think it's important to be 100% on target for merging this.
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.
Makes sense. No, the only dev interface is the query
macro, so not a big deal here.
src/granite/select.cr
Outdated
module Granite::Select | ||
struct Container | ||
property custom | ||
getter table_name, fields |
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.
Since you’re target is to support multiple tables, shouldn’t each field have a paired table?
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.
@robacarp there may be no tables or they may be fields that are calculated. When this is a custom query, the table_name will not have any meaning.
What I think may be a bigger issue is all of the transactional methods are still included when a custom query is provided. These methods should be excluded like save
and destroy
or at least throw runtime exceptions if you attempt to use them. But it would be better to catch these at compile time.
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.
@drujensen Agreed. I think the next step (and I'll write up an issue to discuss this) is to go with your original suggestion in #184 and fully break this out into a ViewModel, which will eliminate the transactional methods (and, hence, no need for compiler check).
src/adapter/sqlite.cr
Outdated
stmt << " FROM #{quote(table_name)}" | ||
stmt << " WHERE #{quote(field)}=:id LIMIT 1" | ||
def select_one(query : Granite::Select::Container, field, id, &block) | ||
if query.custom.size > 0 |
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.
change custom
to a nil-able property and do not initialize it to "". property custom : String?
Then check for nil here instead of size
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.
I think you can get rid of the if
blocks with initial_statement = query.custom || String.build do |stmt|
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.
Great - thank you for suggestions. Done and done.
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.
Excellent PR. 👍 Some minor corrections requested.
@drujensen I believe your concerns were addressed
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 PR (#184 & #200) allows you to customize the SQL used in the SELECT portion of the query (or the entire query if necessary) by adding the
query
macro.The major limitation is that when using a highly-modified
query
, the save/update functionality of the model will likely break. In the issue @drujensen suggested taking a more complete View Model approach, and I agree with that entirely, but wanted to start with a slightly narrower scope. So this is "View Model Lite". Baby steps. Likewise,find
may also break depending on how the query is modified.Also, naming is hard. I'm not wedded to any of the names used, and particularly with things like Query, Select, etc., things might get complex.
(PS - Please feel free to rip to shreds :) I'm new to this type of contribution so am eager to learn & improve in both style and substance. Happy to make as many changes as needed.)