Coder Social home page Coder Social logo

phersistence's Introduction

Phersistence

Run tests:

$ php cli.php associations
$ php cli.php constraints
$ php cli.php fields

Optimizations for has-one

A has-one B

a: A b1, b2: B

$d->create_table('b');

$d->create_table('a');
$d->add_column('a', 'b_id', 'int', true);
$d->add_fk('a', 'b_id', 'fk_a_b', 'b', 'id');

Note: there are two kinds of is_dirty, one is the flag maintained for each hasone attribute and _id field, and the second is evaluated on save/update considering the values of both hasone attribute and _id field. For instance, if the final value for one of them is NULL, buy in the middle there were different values assigned before the save happened, then on save/update the NULL values of either field should be evaluated alongside with the value of the is_dirty flag of each attribute, that is to know the final value that will be used in the dirty check.

Without is_dirty per eahc has-one:

a->b_id a->b case
NULL NOT_LOADED b is not set
NULL NULL b is not set
NULL b1 b was set after a was loaded but is not yet saved
n NOT_LOADED b is set but not loaded, lazy load from db
n NULL b is set but was set to null and a wasn't updated yet
n b1 b is set and loaded, if b->id is different from n, b had a previous value and a wasn't updated yet (this case is only solved by an array of dirty attributes in a)

With is_dirty per each has-one association:

A. is_dirty_b should be true when b is modified in these ways:

  1. b = NULL, then b = b1
  2. b = b1, then b = NULL
  3. b = b1, then b = b2 / b_id != b2->id
  4. b = NOT_LOADED, then b = b1 / b_id != b1->id

The user shouldn't be able to set NOT_LOADED.

B. is_dirty_b_id should be true when b_id is modified in these ways:

  1. b_id = n, then b_id = NULL
  2. b_id = NULL, then b_id = n
  3. b_id = n, then b_id = m / n != m

Table for changes in a->b and how they affect the a->is_dirty_b:

All cases maintain a->b_id unchanged.

a->b_id a->b a->is_dirty_b case
NULL NOT_LOADED false not possible (if b_id = NULL, then b != NOT_LOADED)
NULL NOT_LOADED true not possible 1
NULL NULL false b is not set
NULL NULL true not possible 2
NULL b1 false not possible 3
NULL b1 true b = NULL, then b = b1 (A.1)
n NOT_LOADED false b is set but not loaded yet
n NOT_LOADED true not possible 1
n NULL false not possible 4
n NULL true b = b1, then b = NULL (A.2)
n b1 false b is set and loaded and n = b1->id
n b1 true b = b1, then b = b2 / b_id != b2->id, or, b = NOT_LOADED, then b = b1 / b_id != b1->id (A.3 or A.4) 5

[1]: is_dirty_b can't be true because the user can't set NOT_LOADED [2]: is_dirty_b can't be true because b_id is still NULL, what could occur is b_id and b are NULL, then b is set to b1 without saving a, then b is set to NULL again, Phersistent should detect this case and resent the is_dirty_b to false by checking the value of b_id. [3]: is_dirty_b can't be false because if b_id didn't change, b was set to b1 without saving a, which means, b should be dirty. [4]: is_dirty_b can't be false because a has a b_id, so b should be NOT_LOADED or b1, in this case the user did b = NULL, so b should be dirty. [5]: the final state of this case can't differentiate if the previous value was NOT_LOADED or b1, either way the dirty flag is on because the newly assigned instance of b has a different id from b_id, b1->id could even be NULL.

Table for changes in a->b_id and how they affect the a->is_dirty_b_id:

All cases maintain a->b unchanged.

a->b_id a->b a->is_dirty_b_id case
NULL NOT_LOADED false not possible 6
NULL NOT_LOADED true b_id = n, then b_id = NULL (B.1)
NULL NULL false b is not set
NULL NULL true not possible (at the save/update evaluation, could happen in the is_dirty_b_id) 7
NULL b1 false not possible 8
NULL b1 true b_id = n, then b_id = NULL (B.1)
n NOT_LOADED false a loaded from the database without any changes
n NOT_LOADED true b_id = n, then b_id = m / n != m (B.3)
n NULL false not possible 9
n NULL true b_id = NULL, then b_id = n (B.2)
n b1 false a loaded from the database and b was accessed to read, so it was loaded
n b1 true same as above, and includes: b_id = n, then b_id = m / n != m (B.3)

[6]: if this case happens is because b_id wasn't NULL and was set as NULL, so the is_dirty_b_id should be true. [7]: is_dirty_b_id can't be true because b = NULL and b_id is NULL too (this should be checked before save because in the middle b_id could be set to something then to NULL again) [8]: this case had a b1 assigned to b but the b_id was set to NULL, so it can't have is_dirty_b_id in false. [9]: if b = NULL, there is no hasone associated so on this case b_id was modified, so is_dirty_b_id can't be false.

phersistence's People

Contributors

ppazos avatar ruthbri avatar

Stargazers

 avatar

Watchers

James Cloos avatar  avatar  avatar

phersistence's Issues

save cascade should detect dirty and updates

  1. save cascade is now trying to insert all has one
  2. it should check if the associated has one has no id, save
  3. if the link is null but the FK field is not null, save should save the FK but not the object
  4. if linked instance has id and is dirty, save the FK value and update the associated instance
  5. if linked instance has id and is not dirty, dont save the associated instance

If think we always need to save the FK field if set because if current instance is dirty, the field that might be changed is the FK.

Add raw query execution on Phersistent

Need to do some complicated queries, and to do them correctly we'll need to implement a query builder. Since we currently don't have time for this, as a shortcut we'll add raw SQL execution.

Save: detect duplicate errors for unique fields

  1. save an instance on a table with unique
  2. save another instance with the same value on the unique column
  3. check the MySQL error returned for the unique violation, that error should reach the top level PhInstance so the error can be shown to the user

Database PKs should be UUIDs to avoid lookups for the latest int in auto increment

Needs more memory to store UUIDs but requires less queries to the DB to get new ids for INSERTS.

Also avoids the loops in the instances to wait for parts to get the ids and then set and update with callbacks as we did in Yupp.

function guidv4($data)
{
    assert(strlen($data) == 16);

    $data[6] = chr(ord($data[6]) & 0x0f | 0x40); // set version to 0100
    $data[8] = chr(ord($data[8]) & 0x3f | 0x80); // set bits 6-7 to 10

    return vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($data), 4));
}

if (function_exists("openssl_random_pseudo_bytes"))
{
   echo guidv4(openssl_random_pseudo_bytes(16)) ."\n";
   echo guidv4(openssl_random_pseudo_bytes(16)) ."\n";
   echo guidv4(openssl_random_pseudo_bytes(16)) ."\n";
   echo guidv4(openssl_random_pseudo_bytes(16)) ."\n";
   echo guidv4(openssl_random_pseudo_bytes(16)) ."\n";
 }
if (function_exists("random_bytes")) echo guidv4(random_bytes(16));

Pre save cascade hasMany

  1. Add functions to detect the type of relationship one_to_many or many_to_many
  2. Add functions to detect the owner of a hasMany relationship
  3. By default, one_to_many should be mapped with backlinks and many_to_many with join table. Need to get the correspondent table representations from PhInstances with hasMany

Add NullPhersistentInstance class that can handle any method call without throwing an exception

Let's say we have A has one B.

$a = $A->create();
$b = $a->getB(); // is null
$b->getAttr(); // throws an exception

Si we need to do this every time we need an attribute from $b:

if ($b != null) $b->getAttr();

This difficult how edit screens are programmed. Since we need to check has ones to not be null before accessing their fields, making the code more verbose.

This could be simplified by returning an instance of NullPhersistentInstance instead of null for $b, that can handle getXXX methods, always returning null for simple attrs and another NullPhersistentInstance for has ones.

For this to work, the definition of the NullPhersistentInstance should be the same as the original class, on this example B. So the NullPhersistentInstance knows which attrs are simple and which are has ones.

With has many we don't have issues since we will always return instances of PhCollection.

Verify values set in the instances

Values should be compliant with the declared type.

Date / Time / Datetime values should be compliant with the ISO8601 extended format

// test date to iso 8601
echo (new DateTime('17 Oct 2008'))->format('c') ."\n"; // TZ with :
echo (new DateTime('17 Oct 2008'))->format(DateTime::ATOM) ."\n"; // same as 'c'
echo (new DateTime('17 Oct 2008'))->format(DateTime::ISO8601) ."\n"; // TZ as -0300 without the :
echo gmdate('c', strtotime('17 Oct 2008')) ."\n"; // UTC with +00:00
echo gmdate(DateTime::ATOM, strtotime('17 Oct 2008')) ."\n"; // UTC with +00:00

All these have the T time separator.

Add serialized array type for model fields

Field type defined as self::SARRAY (serialized string array)

On the model use

  • pushToXXX(val) to add a value to the array, adds even if value is duplicated, to avoid dups use hasXXX(val)
  • delFromXXX(val) to delete a value, all occurrences of the value
  • hasXXX(val) true if the value is in the array
  • getXXX() normal get will retrieve the array so it can be traversed

When saving, the array will be serialized to string.
When an instance is loaded, the array from the database will be parsed.

Save cascade hasMany only inserts

  1. Get the right table representation from a PhInstance with hasMany relationship
  2. Save cascade the collection (only inserts for now)
  3. Update the ids on the instances, the hasMany items should be all saved with ids set in memory

Strings with double quotes break inster query

The "1" Wheel..." is broken by the " in the middle of the string:

INSERT INTO hcpcs(code, name, deleted, class) VALUES ("E0962", "1" Wheelchair Cushion", false, "model\HCPCS")

The strings should be escaped in PHP.

Add updates over existing records

  1. single table inheritance
  2. update in cascade, should save associated has ones that are new and update existing
  3. add dirty bit, should be updated to false when the update happens
  4. don't update if not dirty
  5. set fields and has ones should turn on the dirty bit

Support a query execution buffer

A session that can flush all queries when it ends, but with optional flush of specific queries or the whole buffer under demand.

Also the flushes can be marked as transactional. A callback can be set to be notified of rollbacks and errors.

All queries should be transactional, specially on inserts and updates.

Detect empty date values on insert/update and transform to NULL

In some MySQL versions, the empty string for dates just saves a default 0000-00-00 date.
In others, saving an empty string in date/datetime fields, gives an error.

If the value in the instance is empty, and the attribute is date/datetime, put a NULL in the insert/update queries.

Add default value to get methods

PhersistentInstance getAttr dynamic method should have an optional parameter "default_value", if the value in the instance is null, return that default value.

By default, the default_value is null

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.