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
[WIP] Query Builder V2 #318
Conversation
just to make sure .. you are basing this on PHPCR master where the selector name is no longer optional? phpcr/phpcr#68 .. there are related PRs on phpcr-utils, jackalope* |
I will do, I havn't started mapping anything to the PHPCR QOM yet. Although I do imagine that we will always have a selector one way or another. The question is what should come first: User must define - first argument: $qb->select()->column('s', 'property_name'); or selector is optional second argument, but we automatically generate one: $qb->select('property_name');
$qb->where()->equals()->propertyValue('propety_name', 'a'); So question is, in general: $propertyName before $selectorName or vice-versa? |
I think should have a default selector name (f.e. explicit selector
equivalent using the implicit selector:
|
ok, makes sense. Another question: In my current model I do not include the column name in "column". In an ODM this seems (to me) to be pointless, as indeed does the "column" terminology. I imagine th euse case is to partially hydrate objects? If so, then $qb->select()->property('foo')->property('bar') would make more sense. |
yeah we need to talk about object fields, not phpcr properties (or |
Just to update, this is alot of work (lots of classes for this architecture). Making steady progress. Don't expect this to be done before wednesday however. |
I will try and set a day (or two) aside to finish this off this following week. |
); | ||
} | ||
|
||
public function testApi1() |
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 is what the API looks like now ..
ok, have finished the complete API (or at least a first prototype). Next up is the QB => Phpcr Query converter. |
->end() | ||
->from() | ||
->joinInner() | ||
->left()->document('foobar', 'a')->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.
like i said before .. this makes no semantical sense. a join isn't a left and a right join. you join onto an existing set of nodes and there you can use a left or right join to determine how missing nodes in the existing set or the set being joined should behave.
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 is Phpcr terminology I believe, see the JoinInterdace. We can sort these little things out later, I'm still not 100% on the architecture.
Lukas Kahwe Smith notifications@github.com wrote:
array('from', 'From'),
array('orderBy', 'OrderBy'),
array('select', 'Select'),
);
- }
- public function testApi1()
- {
$this->node
->select()
->property('foobar', 'a')
->property('barfoo', 'a')
->end()
->from()
->joinInner()
->left()->document('foobar', 'a')->end()
like i said before .. this makes no semantical sense. a join isn't a
left and a right join. you join onto an existing set of nodes and there
you can use a left or right join to determine how missing nodes in the
existing set or the set being joined should behave.
Reply to this email directly or view it on GitHub:
https://github.com/doctrine/phpcr-odm/pull/318/files#r5918711
Sent from my Android device with K-9 Mail. Please excuse my brevity.
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.
Ah you are referring to https://github.com/phpcr/phpcr/blob/master/src/PHPCR/Query/QOM/JoinInterface.php#L32
As someone with a strong SQL background I find this quite confusing and also doesn't match SQL2:
http://www.h2database.com/jcr/grammar.html#join
But I guess there is some sense in following QOM for a QB.
However I still do not understand why this would be preferred over:
->from('foobar', 'a'))
->joinRightInner('barfoo', 'b')
..
->from('foobar', 'a'))
->joinRightInner('barfoo', 'b')
->joinRightInner('barfooca', 'c')
etc.
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.
Well as you see in the API the join also needs a JoinCondition, it needs three objects. We cannot use the "where" to specify the join condition without doing some pretty confusing abstractions I imagine.
The concept does make sense to me as is, especially when you think in terms of Sources not tables. i. e. you select from a Join source.
Hopefully I will get back online soon and finish the prototype off.
Lukas Kahwe Smith notifications@github.com wrote:
array('from', 'From'),
array('orderBy', 'OrderBy'),
array('select', 'Select'),
);
- }
- public function testApi1()
- {
$this->node
->select()
->property('foobar', 'a')
->property('barfoo', 'a')
->end()
->from()
->joinInner()
->left()->document('foobar', 'a')->end()
Ah you are referring to
https://github.com/phpcr/phpcr/blob/master/src/PHPCR/Query/QOM/JoinInterface.php#L32As someone with a strong SQL background I find this quite confusing and
also doesn't match SQL2:
http://www.h2database.com/jcr/grammar.html#joinBut I guess there is some sense in following QOM for a QB.
However I still do not understand why this would be preferred over:
->from('foobar', 'a')) ->joinRightInner('barfoo', 'b')
..
->from('foobar', 'a')) ->joinRightInner('barfoo', 'b') ->joinRightInner('barfooca', 'c')
etc.
Reply to this email directly or view it on GitHub:
https://github.com/doctrine/phpcr-odm/pull/318/files#r5953344
Sent from my Android device with K-9 Mail. Please excuse my brevity.
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 from()->document('Document') is a bit awkward (and join is the special case, not the standard case). i would prefer from('Document')->end() with optional ->joinSomething after that. the first from needs no condition. only the join with the next document class, so we could provide the join condition there. and i think having both left and right of a join be another join would start to create funny precedence questions that do not exist in SQL2.
i won't veto against the empty from() but i would much prefer to follow lukas' suggestion.
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 it is important to remember that this QB is directly built up from the PHPCR QOM, this is how the QOM does it, and I think abstracting this behavior would give people wrong ideas about what actually happens.
I think there might be some scope for convenience methods, i.e. fromDocument
, fromJoin
and addJoin[Left|Foo]
, but essentially I am pretty sure that there is nothing wrong with the current API.
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.
okay, i give in :-)
ok, this is getting closer to being finished. I think one or two more hacking sessions. Despite that I had another (slightly painful) thought last night that perhaps the current query builder could be improved if we were to implement a flavor of DQL. i.e. $qb->where($qb->expr()->eq('UpperCase(DocumentName(a.foobar))', 'FOOBAR'));
$qb->createQuery('SELECT sel_1.foobar FROM Document\FooBar sel_1 WHERE DocumentName(sel_1.bar) = 'foo'); That would certainly be much more consistent with the Doctrine way of doing things. Will finish this in anycase. @lsmith77 how do join conditions work in SQL2 ? |
protected function walkSourceJoin(SourceJoin $node) | ||
{ | ||
$left = $this->dispatch($node->getChildOfType('SourceJoinLeft')); | ||
$riht = $this->dispatch($node->getChildOfType('SourceJoinRight')); |
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 riht
and not right
?
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.
Err, symmetry :) Can change..
On Sun, Aug 25, 2013 at 05:42:47AM -0700, David Buchmann wrote:
In lib/Doctrine/ODM/PHPCR/Query/QueryBuilder/BuilderConverterPhpcr.php:
$meta = $this->mdf->getMetadataFor($node->getDocumentFqn());
$this->selectorMetadata[$node->getSelectorName()] = $meta;
// get the PHPCR Selector
$selector = $this->qomf->selector(
$meta->getNodeType(),
$node->getSelectorName()
);
return $selector;
- }
- protected function walkSourceJoin(SourceJoin $node)
- {
$left = $this->dispatch($node->getChildOfType('SourceJoinLeft'));
$riht = $this->dispatch($node->getChildOfType('SourceJoinRight'));
why riht and not right?
—
Reply to this email directly or [1]view it on GitHub.References
Visible links
well eventually a DQL for phpcr-odm would be cool, but lets not try to do this here and now, it will be another big pile of work. (defining all the syntax and implementing another parser). i think the orm also has both, a query builder and the DQL. |
My concern is that IF we have DQL then the existing QueryBuilder model On Sun, Aug 25, 2013 at 05:45:37AM -0700, David Buchmann wrote:
|
ok, this /should/ actually work now, I am half way through documenting the classes, although do not currently have sufficient internet to pull in the dependencies required for functional testing. @dbu or anybody else who uses PHPStorm/Eclipse/other smart IDE, I imagine one of the benefits of this approach is auto-completion, will specifying the return type in the DocBlock suffice? Could somebody check if auto-completion works with this API? |
when you say "work" you mean in the real world .. but the tests have just not been updated? |
I mean "in theory". I havn't had the chance to do functional tresting, so some integrations with ODM may not be there, but in theory the the qb is finished. If anyone wants to test it out that would be great, if not I will finish when I have stable internet connection. |
Just an update, this is getting closer all the time, although much more work then I ever imagined. I have droped lop() and rop() as discussed, added |
ok, this is now ready for review. all the tests pass. Still missing is an "addJoin" type of functionality. I guess such functionality would look something like the following: $qb->addJoinInner()
->right()->document('..')->end()
->condition()->equi(..)->end(); Depending on if we keep "left(), right() and condition()" in the "join factory"
|
needs a rebase |
Rebased. |
seems like there is an issue in the tests requiring PHP 5.3 but there are also 2 failures on PHP 5.4 |
what would be the best test case to look at to see the real world use? is there more of a functional test as well? |
https://github.com/doctrine/phpcr-odm/pull/318/files#diff-55 for afunctional test, or the BuilderTest for a full exposition of the API. See als the doc PR:doctrine/phpcr-odm-documentation#29 |
thx .. will try to review this today on my way to ezsummercamp. |
i pushed a few fixes in #323 also one note order for the selector name should always be last, default to 'a' .. and actually maybe the default should be something longer .. like |
- Disabled QB join functionality temporarily - Swaped selectorName to last argument where applicable - findBy ordering now accepts array($field => 'asc|desc') as with doctrine ORM
Right.. so I have added the changes from @lsmith77 's PR, I am throwing Exceptions when people try to do joins (joins do work but I am unsure about how they should work, so don't want to roll them out yet) and havesd swaped the selectorName argument around where applicable. |
there seems to be a PHP 5.3 issue in the test suite: as for the doctrine dbal failures, i just pushed a fixed to master that will hopefully fix this so that you then just need to rebase on master. btw once we have this PR merged, the next step is preparing for the PHPCR BC breaks: |
@@ -48,6 +48,7 @@ | |||
new \PHPCR\Util\Console\Command\WorkspaceQueryCommand(), | |||
new \PHPCR\Util\Console\Command\NodeTypeRegisterCommand(), | |||
new \Doctrine\ODM\PHPCR\Tools\Console\Command\RegisterSystemNodeTypesCommand(), | |||
new \Doctrine\ODM\PHPCR\Tools\Console\Command\DumpQueryBuilderReferenceCommand(), |
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 guess you decided in the end to include it? fine for me
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.
yeah.. I might modify it to make it dump the rst reference, or delete it yet. In any case let's not bootstrap it in the bundle.
Lukas Kahwe Smith notifications@github.com wrote:
@@ -48,6 +48,7 @@
new \PHPCR\Util\Console\Command\WorkspaceQueryCommand(),
new \PHPCR\Util\Console\Command\NodeTypeRegisterCommand(),
new
\Doctrine\ODM\PHPCR\Tools\Console\Command\RegisterSystemNodeTypesCommand(),
- new
\Doctrine\ODM\PHPCR\Tools\Console\Command\DumpQueryBuilderReferenceCommand(),i guess you decided in the end to include it? fine for me
Reply to this email directly or view it on GitHub:
https://github.com/doctrine/phpcr-odm/pull/318/files#r6352958
Sent from my Android device with K-9 Mail. Please excuse my brevity.
went through the code and made a few comments. one more thing I just merged http://github.com/doctrine/phpcr-odm/pull/322 which aimed to get rid of all use of exceptions outside of the phpcr odm namespace |
cheers lukas.. I have added PHPCR exceptions for BadMethodCall and Runtime, added |
@@ -0,0 +1,109 @@ | |||
<?phph |
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.
small typo
getting there .. a small typo and the php 5.3 issue left .. |
- Added Runtime and BadMethodCall Exceptions - Added @IgnoreAnnotation - Removed extra lines
there is now only a minor issue left with doctrine dbal |
/** | ||
* Descendant document constraint: | ||
* | ||
* $qb->where()->descendantDocument('/ancestor/path', 'sel_1') |
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.
noticed that when you renamed the methods you missed the comments
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.
yeah, I noticed that too :) Will be fixed in #326
Lukas Kahwe Smith notifications@github.com wrote:
*
\* @param string $path
\* @param string $selectorName
*
\* @factoryMethod
\* @return ConstraintSame
*/
- public function same($path, $selectorName)
- {
$selectorName, $path));return $this->addChild(new ConstraintSame($this,
- }
- /**
\* Descendant document constraint:
*
\* $qb->where()->descendantDocument('/ancestor/path', 'sel_1')
noticed that when you renamed the methods you missed the comments
Reply to this email directly or view it on GitHub:
https://github.com/doctrine/phpcr-odm/pull/318/files#r6367502
Sent from my Android device with K-9 Mail. Please excuse my brevity.
$qm = $this->session->getWorkspace()->getQueryManager(); | ||
$qomf = $qm->getQOMFactory(); | ||
$converter = new BuilderConverterPhpcr($this, $qomf); | ||
$builder->setConverter($converter); |
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.
is the converter an optional dependency of the querybuilder? otherwise i would prefer constructor injection to make sure the builder always has a converter with it...
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.
Constructor injection would make more sense I guess, at the slight cost of having to mock a Converter in the tests.
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 that is a cost that is not too high :-)
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.
But then, I guess this class will be used quite alot in tests (mocking this class would be a complete pain). I was going to suggest also that we might want to set different converters at runtime, although, short of using this QB as an abstract interface for the ORM, not sure what the use case would be.
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.
to use different converters, you could also just instantiate new query
builders.
Todo
Part 1
addSelect
,addJoin
, etc)lop
androp
. They add about 28 characters to every comparison and are only useful for AutoCompletePart 2
Query\QueryBuilder
toQuery\Builder