pear2 / Net_RouterOS

This package allows you to read and write information from a RouterOS host using the MikroTik RouterOS API protocol.
http://pear2.php.net/PEAR2_Net_RouterOS
242 stars 116 forks source link

Support the creation of queries from strings #7

Open boenrobot opened 12 years ago

boenrobot commented 12 years ago

While the basic functionality of the Query class works for most cases, it can quickly become difficult to use (or at the very least lead to verbose code) as the size of the query grows.

A more intuitive approach would be the creation of a query from a string. The string itself should use the familiar syntax from shell's "where" argument... with some reduced functionality of course (e.g. there's no regex in queries yet).

Among other things, I'm still wondering what to call it though... Query::parse(), Query::expression(), Query:fromString()...

Max13 commented 6 years ago

@boenrobot I suggest you just use the constructor:

$query = new Query('where adress=10.10.10.10');

Then you tokenize the string on every space and =, !=, >, <, ...

boenrobot commented 6 years ago

The constructor is called internally by static methods with an empty query (before filling it with what the user supplied), but an empty query is not something that a user should be allowed to end up with... So that's a no go.

That said, if you could implement a static method that does the actual tokenization and conversion to query words AND supports proper brackets, I would be very happy to accept a pull request.

Max13 commented 6 years ago

Here is what I have for now: https://gist.github.com/Max13/70880d1e2d421b6f602501ba37e1dcb5

I have 5 tests, including && and ||, but currently I have no clue how to take the parenthesis into consideration, neither if regex is the best method (probably not).

boenrobot commented 6 years ago

The query is basically expressed in reverse polish notation, meaning one needs to implement https://en.wikipedia.org/wiki/Shunting-yard_algorithm after properly tokenizing the whole thing... Regex in general is the best way to tokenize it, but whether your specific one is the best is a separate matter, and I'm not sure about that.

Also, keep in mind that there are a few more things one can do in a where in addition to brackets (and which do have query equivalents). Notably, what I see missing is negation of expressions (e.g. !(a || b)), "or equals" operators ("prop >= value" should be translated to "(prop > value || prop = value)" under the hood, and analogously for "<="), and I'm also not sure if your regex would support "is set" checks, e.g. propX && propY="" being equal to

?propX
?propY=
?#&

and !propX && !propY="" being equal to

?-propX
?-propY=
?#&