Page 1 of 2

PSQLx2.0 overview and support

Posted: Wed Oct 29, 2008 10:50 am
by crazycoders
Hi, here is the first jet of PSQLx2.0 which is a replacement to PLUQ (An in memory query builder/array query operator). This new version of PLUQ first bases itself on types to allow command chaining to be possible. I'd like everyone to review the first jet of it.
  • interface iconvertible
  • interface ivalued
  • class psqlx_boolean
  • global function box

Code: Select all

 
<?php
//Interface allowing an object to be converted to boxed and unboxed versions of himself
interface psqlx_iconvertible{ 
    //Non boxed conversions
    public function unbox();
    //Boxed conversions
    public function toint8($signed = true, $lowbound = NULL, $highbound = NULL);
    public function toint16($signed = true, $lowbound = NULL, $highbound = NULL);
    public function toint24($signed = true, $lowbound = NULL, $highbound = NULL);
    public function toint32($signed = true, $lowbound = NULL, $highbound = NULL);
    public function toint64($signed = true, $lowbound = NULL, $highbound = NULL);
    public function tosingle($decimals = NULL, $lowbound = NULL, $highbound = NULL);
    public function todouble($decimals = NULL, $lowbound = NULL, $highbound = NULL);
    public function tostring($lowbound = NULL, $highbound = NULL, $regexp = NULL);
    public function todatetime($lowbound = NULL, $highbound = NULL);
    public function toboolean();
    public function tointerval();
    public function toarray($strict = true);
}
//Interface allowing an object to represent a value
interface psqlx_ivalued{ 
    public function setValue($value);
    public function getValue();
}
 
//Class representing a boolean value
if(!class_exists('psqlx_boolean')){
    class psqlx_boolean implements psqlx_iconvertible {
        private $d = false;
        public function __construct($value){ $this->setValue($value); }
        //psqlx_iconvertible
        public function unbox(){ return $this->d; }
        public function toint8($signed = true, $lowbound = NULL, $highbound = NULL){  }
        public function toint16($signed = true, $lowbound = NULL, $highbound = NULL){  }
        public function toint24($signed = true, $lowbound = NULL, $highbound = NULL){  }
        public function toint32($signed = true, $lowbound = NULL, $highbound = NULL){  }
        public function toint64($signed = true, $lowbound = NULL, $highbound = NULL){  }
        public function tosingle($decimals = NULL, $lowbound = NULL, $highbound = NULL){  }
        public function todouble($decimals = NULL, $lowbound = NULL, $highbound = NULL){  }
        public function tostring($lowbound = NULL, $highbound = NULL, $regexp = NULL){  }
        public function todatetime($lowbound = NULL, $highbound = NULL){ }
        public function toboolean(){ }
        public function tointerval(){ }
        public function toarray($strict = true){ }
        //psqlx_ivalued
        public function setValue($value){
            if($value !== true && $value !== false){ throw new Exception($value.' is not of boolean type, cannot store this value into a psqlx_boolean.'); }
            $this->d = $value;
        }
        public function getValue(){ return $this->d; }
        //Quick access to set/getvalue through magic methods
        public function __set($name, $value){
            switch($name){
                case 'v':
                case 'val':
                case 'value':
                    return $this->setValue($value);
                default: throw new Exception('Unknown '.$name.' in psqlx_boolean');
            }
        }
        public function __get($name){
            switch($name){
                case 'v':
                case 'val':
                case 'value':
                    return $this->getValue();
                default: throw new Exception('Unknown '.$name.' in psqlx_boolean');
            }
        }
    
    }
}
//This function boxes values into objects for psqlx2.0
function box($value){
    if(is_null($value)){ return $value; }
    if(is_bool($value)){ return new psqlx_boolean($value); }
    if(is_object($value)){ return $value; }
    if(is_resource($value)){ return $value; }
    if(is_string($value)){ return ''; }
    throw new Exception('Unable to box scalar $value ('.$value.') to a boxed psqlx type');
}
?>
 

Code: Select all

 
<pre>
<?php
include('psqlx.types.php');
$d = box(true);
$d->v = false;
$d->val = false;
$d->value = false;
$d->v = true;
$d->val = true;
$d->value = true;
$d->v = 1;
$d->val = 2;
$d->value = 3;
?>
</pre>
 
Tell me what you think please!

Re: PSQLx2.0 overview and support

Posted: Wed Oct 29, 2008 11:42 am
by allspiritseve
Sorry, what is this used for?

Re: PSQLx2.0 overview and support

Posted: Wed Oct 29, 2008 12:04 pm
by crazycoders
It is a type safe implementation for a future query/data manipulation structure

Re: PSQLx2.0 overview and support

Posted: Wed Oct 29, 2008 12:24 pm
by allspiritseve
That's over my head. :D

Re: PSQLx2.0 overview and support

Posted: Thu Oct 30, 2008 11:41 am
by crazycoders
Allright, getting somewhere, i'd like to invite anyone to test my command chaining, boxing/unboxing of values mechanism.
I will post a few examples that you can look at here. I will not copy the code anymore cause it is starting to be quite big :)

http://www.allianceunisport.com/pluq2/test.php
http://www.allianceunisport.com/pluq2/test.phps
http://www.allianceunisport.com/pluq2/psqlx.types.phps
http://www.allianceunisport.com/pluq2/p ... tions.phps

You are authorized to copy the psqlx libraries on your server and test and play around but you are in no rights to continue, resell, use, in production or in development these libraries. They are not finished not fully tested. I need feedback and bug reports first.

Operations still missing are:
  • BIN (DecToBin)
  • HEX(DecToHex)
  • UNHEX(HexToDec)
  • OCT(DecToOct)
  • INSTR(strpos)
  • LOCATE(strpos but with a start pos)
  • REPLACE(str_replace)
  • LPAD(str_pad, LEFT_PAD)
  • RPAD(str_pad, RIGHT_PAD)
  • REPEAT(str_repeat)
  • REVERSE(str_Rev)
If you don't understand the use for this library, then ask away, i will gladly explain it to you.

Re: PSQLx2.0 overview and support

Posted: Thu Oct 30, 2008 4:43 pm
by Christopher
I have not followed this thread, but I assume that you are generating SQL ... right? What does "boxing/unboxing" mean?

Re: PSQLx2.0 overview and support

Posted: Thu Oct 30, 2008 4:51 pm
by josh
crazycoders wrote:If you don't understand the use for this library, then ask away, i will gladly explain it to you.
Let's hear it.. So far all you've shown is that it records some arbitrary integers by breaking encapsulation, I guess I may be dense

Re: PSQLx2.0 overview and support

Posted: Thu Oct 30, 2008 8:27 pm
by crazycoders
It's a type safe implementation of a query system that will be able to act on memory data such as arrays and on database data. I already have an implementation of this but it's use what not enough open and flexible. With this new concept (which is in fact the same thing that happens when php gets parsed and ran, its one of the concept behind code parsing) i can chain and create endless permutations (safely typed and checked) that can execute over any kind of data, or resolve into SQL code that will be applied on an SQL server.

When all the work is done, you could do this with ease:

$mycars = $cars->where($cars->driverid->equals($_REQUEST['id']))->sort($cars->make, $cars->model, desc($cars->edition))

Then mycars would be what we call a psqlx datasource that can be enumerated, passed on to any object that works with datasources, such as grid controls. The datasource object is already created but not really usable since it is in the previous 2.0 version that never made it so it is not compatible but it allowed me to enumerate the resource and automatically cast to a specific class and manage objects.

The previous ORM that i did that was compatible manages datacaching completely and supports relationships with other objects automatically.

This 2.0 implementation of PSQLx will allow you to do virtually anything in a code environment whatever it's datasource is, i just wish there are more early binding possible it would make the code even more type safe.

Another example is this:

$a = box(array('apple', 'orange', 'banana'));
$b = $a->where($a->index(0)->contains('an'))->sort(desc($a->index(0)));

This would return an array {'orange', 'banana'}... Ok, it could have been done with a user function and an array_walk, but it's not really beautiful. With Lambda expressions coming in the next version (5.3), PSQLx will shine even more and resemble MSLINQ much more since MSLINQ is in fact a Lambda Language Construct. Just so much powerful than mine.

Re: PSQLx2.0 overview and support

Posted: Thu Oct 30, 2008 8:36 pm
by crazycoders
arborint wrote:I have not followed this thread, but I assume that you are generating SQL ... right? What does "boxing/unboxing" mean?
Partly, juste read the previous post... About boxing and unboxing it's a mechanism used in OOP to encapsulate scalar values into objects and unboxing means you get the scalar value back from the object.

Edit: Boxing is automatic in compiled language, sadly this is not possible yet with PHP so thats why you see box/unbox everywhere.

using BOX(x) you create a boxed version of an object that offers a tapesafe implementation of itself and a whole lot of functions to use on it. For example, boxing a string then gives you directly access to loads of string manipulation functions, eventually, there will also be comparison operators and conversion operators. All operations you execute create a chain that becomes a chain of operation that stays it this way until ->x() 'ed. (Or executed) If you eXecute a chain it returns a boxed version, to save yourself from unboxing using ->unbox(), or ->u(), you can simple call ->xu();

Finaly, if the command chain is to be ran on an SQL datasource, you or the datasource will call ->s() to generate the SQL version of the command chain.

Command chains are vital in this technique because it will allow you to subquery memory data or sql data easily and do complex selection, aggregation and sorting operations.

Re: PSQLx2.0 overview and support

Posted: Thu Oct 30, 2008 10:37 pm
by Christopher
That sounds like a way to do this. I just can't tell if it is a good way to do this. It strikes me as a little wacky because it seems to expand the problem space beyond what seems necessary -- especially given the portability concerns stated above. But I get a sense of what you are doing.

Re: PSQLx2.0 overview and support

Posted: Mon Nov 03, 2008 12:07 pm
by crazycoders
More changes done to PSQLx2.0, Reformated the test output, refactored and implemented the type conversion better, still a lot of work to do. Finished the string functions, added numeric functions. Tonight i start the dates and date functions...

http://www.allianceunisport.com/pluq2/test.php
http://www.allianceunisport.com/pluq2/test.phps
http://www.allianceunisport.com/pluq2/psqlx.types.phps
http://www.allianceunisport.com/pluq2/p ... tions.phps
http://www.allianceunisport.com/pluq2/p ... tions.phps

I'd need some people to look it up, copy the code and test on their side if there are bugs they can find. It's not a really complex lib to use, but it's concept is.

Re: PSQLx2.0 overview and support

Posted: Mon Nov 03, 2008 12:49 pm
by josh
Could you explain for me how one would use this in a project? Is it basically a repository design pattern implementation? Is its intentions just to enforce type safety?

Re: PSQLx2.0 overview and support

Posted: Mon Nov 03, 2008 1:23 pm
by crazycoders
No, eventually i will bind an ORM on this and you will be able to use it on memory data. For example:

$cars would be globally available and is a direct link to a psqlx_datasource object which represents a table in your database. A datasource is an object you can query, arrays can be datasources, database tables too and anything else that would implement the interface in question is a datasource that you can query in this way.

You could call this:
$usercars = $cars->where($cars->make->equals('honda'))->orderby($cars->year)

And it would return a query... when the query is used in the context of an enumeration such as a forloop, then the data is fetched and all calls to it return the next element from the database (only on each call do i load the data, not all the data is loaded at once) The datasource also allows direct casting of the array information into an object of the type contained by the datasource. So if it is a datatable, you can cast your data into an object type used to manage data in your database. The ORM is in charge of creating the whole object set for your database, the links between the objects and so on.

If we take it differently, this library can also be used to filter out data from an array for example. In the case of an array, the data is already in memory so the enumerator simply builds an index of the items matching the query and accesses them from the original data very quickly. An example:

Code: Select all

$fruits = box(array('apple', 'banana', 'orange', 'kiwi', 'grapes'));
$selectedfruits = $fruits->where($fruits->index(0)->contains('an'))->order($fruits->index(0)->desc());
foreach($selectedfruits as $fruit){
echo $fruit.'<br>';
}

Code: Select all

Would output:
orange
banana
 
This is only a mere and really simple example as the whole data framework supports type safety, casting of data from one time to another, chaining of commands. So you could actually use this to manage data later on and do:

Code: Select all

$fruits->set($fruits->index(1), 'selected')->where($fruits->contains('an'));
And this would create a new column inside the $fruits array and set 'Selected' in the items matching the criterias. You could change the 'selected' by:

Code: Select all

$fruits->index(0)->toupper()->concat(' is selected')
And it would put the uppercase name of the fruit is selected into index1.

I can't start explaining all the uses, but i'm sure, as brillant as you are, that you understand the impact and versatility of this technology.

Re: PSQLx2.0 overview and support

Posted: Mon Nov 03, 2008 1:30 pm
by crazycoders
Additionnaly, note that the ORM bases all of it's schema for the database objects on the typesafety system implemented by PSQLx. All objects come with a fully customizable set of properties that allow direct validation of the data. No more testing before sending to the database. If you set it in the object model, just doing this:

Code: Select all

try{
$myobj->myprop = $_REQUEST['mypropinput'];
$myobj->myprop2 = $_REQUEST['mypropinput2'];
$myobj->myprop3 = $_REQUEST['mypropinput3'];
}catch(psqlx_validationexception $ex){
echo 'Field '.$ex->fieldname.' validation failed: '.$ex->message;
}
I had another thing i wanted to say but i forgot about it, i'll write it in a later message if i remember.

Re: PSQLx2.0 overview and support

Posted: Mon Nov 03, 2008 1:40 pm
by crazycoders
Oh yeah thats it...

If you manipulate memory data within a selection, the data is only manipulated in the returned scalar/array data. For example:

Code: Select all

 
$mydata = box(array(1,2,3,4,5,6,7,8,9,10));
foreach($mydata->select($mydata->index(0)->add(6))->where($mydata->index(0)->greaterthan(8) as $mydataitem){
echo $mydataitem.', ';
}
 
will output:
14, 15, 16

But behind the scene, the $mydata array is not changed, just when the data is accessed using the foreach that the information is altered before being sent to the $mydataitem. Since php copies all information that is not an object, this information is not updated in the original array.

I'm still debating if it will be possible to do this to a table datasource that is supposed to return object mappings to records in the database. If it does, it means i'll have to either force a user to select all the fields one by one or find a way to bypass the type checking system. (It will detect that a field is missing from the array sent to the object constructor.)

If it does apply, what i was thinking is that it would simply return arrays of data instead of objects of the expected type. Thus, all persistence and validation code of the object would be removed. Thats probably the best since the user shouldnt be modifying data going to an ORM object like that. Instead he could just use a query after that to update all the fields he wants accordingly... I'm just rambling here and thinking out loud.