mindplay-dk / sql

Database framework and query builder
Other
17 stars 6 forks source link

Unqualified table-references (or boxed values?) #36

Open mindplay-dk opened 7 years ago

mindplay-dk commented 7 years ago

When building custom INSERT and UPDATE queries, column-references need to be unqualified, which is currently a bit cumbersome - you have to manually unqualify every column-references by explicitly calling getName() as in the following:

$c = $this->schema->child_blocks;

$upsert = $this->db
    ->sql("
        INSERT INTO {$c} ({$c->parent_uuid->getName()}, {$c->column_index->getName()}, {$c->child_uuids->getName()})
        VALUES (:parent_uuid, :column_index, :child_uuids)
        ON CONFLICT ({$c->parent_uuid->getName()}, {$c->column_index->getName()}) DO UPDATE SET {$c->child_uuids->getName()} = :child_uuids
    ")
    ->bind($c->parent_uuid->getName(), $parent_uuid)
    ->bind($c->column_index->getName(), $column_index)
    ->bind($c->child_uuids->getName(), $child_uuids, StringArrayType::class);

This approach has the undesirable side-effect of also unquoting the column-names.

If we could explicitly request a table-instance that produces quoted, but unqualified column-objects, the above could be simplified as:

$c = $this->schema->child_blocks(null); // null meaning "no alias"

$upsert = $this->db
    ->sql("
        INSERT INTO {$c} ({$c->parent_uuid}, {$c->column_index}, {$c->child_uuids})
        VALUES (:parent_uuid, :column_index, :child_uuids)
        ON CONFLICT ({$c->parent_uuid}, {$c->column_index}) DO UPDATE SET {$c->child_uuids} = :child_uuids
    ")
    ->bind($c->parent_uuid, $parent_uuid)
    ->bind($c->column_index, $column_index)
    ->bind($c->child_uuids, $child_uuids, StringArrayType::class);

This allows us to remove all the getName() calls, making this a possible alternative to #35 as well.

We may need to distinguish between NULL and "" in this argument, or provide some other means of explicitly asking for an unqualified table-instance, possibly a factory-method on the Table class itself.

mindplay-dk commented 5 years ago

Alternative proposal:

We could introduce some kind of Value wrapper-type: a kind of boxed value that carries both the colum/type and the value itself - for example:

$user = $schema->user;

$insert = $db->insert($user)
    ->add([
        $user->first_name->value("Rasmus"),
        $user->last_name->value("Schultz"),
    ]);

This way, you wouldn't need to specify column-name as a key - instead, the Column model has a value() factory-method that constructs a Value model, which would have e.g. getName() and getType() methods, which could then be used internally in the query-builders.