atk4 / dsql Goto Github PK
View Code? Open in Web Editor NEWObject-Oriented SQL Query Builder
Home Page: https://agiletoolkit.org/
License: MIT License
Object-Oriented SQL Query Builder
Home Page: https://agiletoolkit.org/
License: MIT License
Query->main_table
property probably is not needed. At least while we don't have join
implemented.
Think of it as - SQL query as such doesn't have "default table" so most likely Query class shouldn't have default (main) table also.
we might need to cross-link it.
for example
http://dsql.readthedocs.org/en/latest/quickstart.html
basic concepts here
they can be clickable.
http://dsql.readthedocs.org/en/latest/quickstart.html#creating-objects-and-pdo
classes are menitoned here - Query and Expression
again same thing.
http://dsql.readthedocs.org/en/latest/quickstart.html#fetching-result
some methods are mentioned here, but not documented either.
getOne, getRow
i think they nee to be defined here
http://dsql.readthedocs.org/en/latest/queries.html#query-modes
Currently we have few tests that run on an actual database. Those must be included in the Travis checks, but travis needs to be configured with MySQL support too.
Test case:
$q = (new Query)->table('employee', 'emp');
$this->assertEquals(
'select `name` from (select * from `employee` `emp`) `derrived`',
(new Query)
->field('name')
->table($q, 'derrived') // <-- this alias is not saved in $args array if table is expression
->render()
);
Currently this generates
select `name` from (select * from `employee` `emp`)
but should be
select `name` from (select * from `employee` `emp`) `derrived`
Currently it complains about non-existant "hook" in github. Maybe the hook can be added manually?
Currently when you need to compare two fields, you would normally type:
$q->where('name','surname';)
But this won't compare two fields, instead it will look for records where name="surname". The second try you would do:
$q->where('name', $q->expr('surname'));
But once again, it's not ideal:
where `name` = surname
It's not using quotes now. The third attempt is:
$q->where('name', $q->expr($q->_escape('surname')));
And unfortunately this won't work, because _escape is protected method.
Please wait for 1.0-beta before fully resolving this issue.
https://codeclimate.com/github/atk4/dsql/src/Query.php
Need to improve issues in this file.
Add support in the Query
class to implement https://en.wikipedia.org/wiki/Hierarchical_and_recursive_queries_in_SQL#Common_table_expression using SQL WITH
clause.
The signature of the function could be the following:
public function with($expr, $table_alias, $fields = [])
public function withRecursive($expr, $table_alias, $fields = [])
The alias in this case should be mandatory (single identifier or array), while expr could be any kind of subtable expression, or even a union. $fields is optional.
To produce the following query
WITH RECURSIVE
cnt(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM cnt WHERE x<1000000)
SELECT x FROM cnt;
you would do:
$expr = newExpression('values(1) union all select x+1 from cnt where x<1000000');
$q = new Query();
$q->table('cnt');
$q->field('x');
$q->withRecursive($expr, 'cnt', ['x']);
It should be possible to execute with() multiple times.
As described here:
http://php.net/manual/en/mysqlinfo.concepts.buffering.php
It is possible to execute unbuffered queries with PDO. We need to make sure that DSQL can still allow it's user to execute unbuffered queries, where the results are streamed, but this mode should be optional.
We also should look in the situations, when we want to execute query while data are still being fetched. Can PDO properly handle that?
That is more suitable and easier to understand.
DSQL has a lot of flexibility, but it's quite difficult to demonstrate with documentation alone.
The idea is to start a new project, that will consist of a very basic PHP files. When you execute those files, they will perform a query and fetch result from a "employee" data-set.
This will make it much easier for new users to learn DSQL.
Question: suppose you have a transaction that adds a new user, that performs multiple operations in DB. This operation calls another routine that adds a new bank account, which also uses a transaction for multiple operations.
Now suppose bank transaction addition operation fails some checks and you want to roll it back. Unfortunately you can't because SQL does not support multiple BEGIN TRANSACTIONS. So the code should somehow throw an exception but I'm not sure how.
Before going public and telling others about our cute new library, we should have some
sort of library.
This now can be done more efficiently since Expression is forked out.
See http://php.net/manual/en/mysqlinfo.concepts.charset.php
I think at this point in time creating non-UTF8 connections might not be even viable. Previously we used set NAMES UTF8, but now we can simply pass this as an argument.
If possible, include "having()" also.
Skip "and" and "or" support (render_or_where)
render_query does not add blank space before 'left'. This does not create any problem with queries, but it looks weird:
select `pi`.`name` from `item` `pi`left join `item2` as `pi_i` on `pi_i`.`item_id` = `pi`.`id` where `pi`.`id` = `_i`.`parent_item_id`
Use the file https://github.com/atk4/dsql/blob/develop/phpunit-mysql.xml as example and create integration for PostgreSQL. Also follow #23 to integrate PostgreSQL into travis.
should be able to
insert ignore
insert delayed
select calc_found_rows
etc
Currently expression support [] arguments and they will consume/parametrize them. We need {} argument support which will consume/escape parameters.
If you try to call Expression->getDebugQuery and don't have SqlFormatter class, then you can get ugly exception from tookit because class_exists()
(here https://github.com/atk4/dsql/blob/develop/src/Expression.php#L467) actually calls spl_autoload_call
which calls toolkit locatePath etc. and if it can not find SqlFormatter.php then it fails :(
Stacktrace:
Exception_PathFinder: File not found
Additional information:
file: SqlFormatter.php
type: php
attempted_locations:
0: \oms\app/lib/SqlFormatter.php
1: \oms\vendor\atk4\atk4/lib/SqlFormatter.php
class: SqlFormatter
namespace:
orig_class: SqlFormatter
\oms\vendor\atk4\atk4\lib\PathFinder.php:461
File Object Name Stack Trace Help
\oms\vendor\atk4\atk4\lib/PathFinder.php:348 oms_pathfinder PathFinder->exception("File not found")
\oms\vendor\atk4\atk4\lib\App/CLI.php:380 oms_pathfinder PathFinder->locate("php", "SqlFormatter.php", "path")
\oms\vendor\atk4\atk4\lib/PathFinder.php:461 oms App->locatePath("php", "SqlFormatter.php")
\oms\vendor\atk4\atk4\lib/PathFinder.php:121 oms_pathfinder PathFinder->loadClass("SqlFormatter")
/: oms_pathfinder PathFinder->{closure}("SqlFormatter")
/: BaseException BaseExceptionspl_autoload_call("SqlFormatter")
\oms\vendor\atk4\dsql\src/Expression.php:467 BaseException BaseExceptionclass_exists("SqlFormatter")
\oms\vendor\atk4\dsql\src/Expression.php:559 atk4\dsql\Query_MySQL atk4\dsql\Query_MySQL->getDebugQuery()
\oms\vendor\atk4\dsql\src/Query.php:1015 atk4\dsql\Query_MySQL atk4\dsql\Query_MySQL->execute()
\oms\vendor\atk4\data\src/Join_SQL.php:235 atk4\dsql\Query_MySQL atk4\dsql\Query_MySQL->delete()
/: __p atk4\data\Join_SQL->doDelete(Object(Model_Payment), "6")
...
methods getOne(), getRow(), getHash() as well as ability to iterate through result set. Must remain compatible with atk4/atk4.
Currently in order to include CASE expression in your field list, one would have to write:
$query->field(new Expression("case {} when [] then {} when [] then {} else null end", [
'status',
'New', 't2.expose_new'
'Used', 't2.expose_used'
]), 'expose');
Similarly how we are tackling orExpr() we can also add support for caseExpr() which should have a more pleasant format:
$query->field($query->caseExpr('status')
->when('New', 't2.expose_new')
->when('Used', 't2.expose_used')
->else(null), 'expose');
Because - performance and I have left some is_null() around:
See if we can run query with multiple connections. Technically it's possible to specify $connection
into Expression::execute()
, but could it result in problems?
Some test-scripts are needed to test query in multiple scenarios:
This needs to be implemented in tests/db
add documentation for order() and limit()
http://dsql.readthedocs.org/en/latest/queries.html#Query::where
only table, field and where is documented.
Query::group() detects comma in the argument and will break
$a->group("date_format(dat, '%Y')");
breaks the line into 2 grouping parameters and escapes only the second one resulting in:
group by date_format(dat, "%Y")
Check if we have any of these methods and if so,then use their mb_ equivalent.
http://php.net/manual/en/ref.mbstring.php
Also we need to add some test-scripts:
because, why keep exceptions in both locations.. ?
http://dev.mysql.com/doc/refman/5.7/en/delete.html supports "partition (p0)" syntax. We might as well add it or document how to add it.
The library currently doesn't seem to support multi field joins, or is there already a way to perform them?
I was thinging something like
SELECT A.*
FROM my_tbl_a A
JOIN my_tbl_b B ON (A.x = B.y AND A.b = B.b)
WHERE ...
I've created a cheat-sheet here:
https://github.com/atk4/dsql#documentation-cheat-sheet
to contain most used functions and link directly into documentation. I'd like someone to help me by simply updating the link to the doc.
This piece of code is found in _render_where
, _render_orwhere
, _render_andwhere
, _render_having
:
if (!isset($this->args['where'])) {
return;
}
It can me moved to __render_where
method to not duplicate code:
if (!isset($this->args[$kind])) {
return;
}
and in previously mentioned methods do simply like this:
protected function _render_orwhere()
{
$ret = $this->__render_where('where');
return $ret ? implode(' or ', $ret) : null;
}
Old DSQL would execute getOne() on the query if you attempt to cast it into string. We should preserve this behaviour as it was widely used.
_consume
wraps only Query
objects in parenthesis and that's OK.
But in case we use Expression
object as table it should be wrapped in parenthesis too. See union example in QueryTest
class.
Now generates:
select * from (select * from `sales`) union (select * from `purchases`)
should generate:
select * from ((select * from `sales`) union (select * from `purchases`)) `derrivedTable`
derrivedTable alias will come from fixing #33
Simple implementation of group by
is also needed.
Looks like you accidentally copy/pasted my name and information into the license in your documentation: https://github.com/atk4/dsql/blob/develop/docs/overview.rst#license
It's used in Expression::_consume()
.
Maybe it should better be interface not trait?
Those should now be easily doable. Create implementation and necessary tests.
See: http://forum.agiletoolkit.org/t/save-null-value-to-mysql-db/172/2
I strongly believe that empty string should never be saved in DB as such. Empty string is the same as NULL in many DB engines already and have no meaning other than NULL.
So DSQL probably should convert empty string to NULL out-of-the-box.
The method has the following signature and body:
public function dsql($properties = [])
{
$q = new self($properties);
$q->connection = $this->connection;
return $q;
}
This meas that, when called from an object that is actually a Query_MySQL
, it'll return a simple Query
instead, shouldn't it be better to use new static()
instead ?
Based on : https://github.com/atk4/dsql/wiki/Awesome-Queries
Create test-cases for complex queries as explained in Wiki.
Old entries (possibly duplicates)
as described in queries.rst
document
Ability easily create expressions off the query.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.