151 lines
2.5 KiB
PHP
151 lines
2.5 KiB
PHP
|
<?php
|
|||
|
|
|||
|
namespace alveolata\sql;
|
|||
|
|
|||
|
// require_once(DIR_ALVEOLATA . '/definitions.php');
|
|||
|
|
|||
|
|
|||
|
/**
|
|||
|
* @param array $expressions {list<string>}
|
|||
|
* @return string
|
|||
|
* @author Christian Fraß <frass@greenscale.de>
|
|||
|
*/
|
|||
|
function conjunction(
|
|||
|
array $expressions
|
|||
|
) : string
|
|||
|
{
|
|||
|
return (
|
|||
|
implode(
|
|||
|
' AND ',
|
|||
|
array_map(
|
|||
|
function (string $expression) : string {
|
|||
|
return sprintf('(%s)', $expression);
|
|||
|
},
|
|||
|
$expressions
|
|||
|
)
|
|||
|
)
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/**
|
|||
|
* @param array $expressions {list<string>}
|
|||
|
* @return string
|
|||
|
* @author Christian Fraß <frass@greenscale.de>
|
|||
|
*/
|
|||
|
function disjunction(
|
|||
|
array $expressions
|
|||
|
) : string
|
|||
|
{
|
|||
|
return (
|
|||
|
implode(
|
|||
|
' OR ',
|
|||
|
array_map(
|
|||
|
function (string $expression) : string {
|
|||
|
return sprintf('(%s)', $expression);
|
|||
|
},
|
|||
|
$expressions
|
|||
|
)
|
|||
|
)
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/**
|
|||
|
* expression to check if two sets (~ 1 column tables) are equal (in their elements, not in their order)
|
|||
|
* warning: won't work for empty sets
|
|||
|
*
|
|||
|
* @author Christian Fraß <frass@greenscale.de>
|
|||
|
*/
|
|||
|
function set_equal(
|
|||
|
string $set1,
|
|||
|
string $set2
|
|||
|
) : string
|
|||
|
{
|
|||
|
// (x \ y) ∪ (y \ x) = {}
|
|||
|
return sprintf(
|
|||
|
'(NOT EXISTS (SELECT value FROM (%s) WHERE NOT (value IN (%s)) UNION SELECT value FROM (%s) WHERE NOT (value IN (%s))))',
|
|||
|
$set1,
|
|||
|
$set2,
|
|||
|
$set2,
|
|||
|
$set1
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/**
|
|||
|
* @param mixed $value
|
|||
|
* @param \Closure $escape
|
|||
|
* @return string
|
|||
|
* @author Christian Fraß <frass@greenscale.de>
|
|||
|
*/
|
|||
|
function format(
|
|||
|
$value,
|
|||
|
\Closure $escape = null
|
|||
|
) : string
|
|||
|
{
|
|||
|
if ($escape === null) {
|
|||
|
$escape = (
|
|||
|
function ($x) {
|
|||
|
$replacements = [
|
|||
|
'\'' => '\'\'',
|
|||
|
';' => '\\;',
|
|||
|
];
|
|||
|
$y = $x;
|
|||
|
foreach ($replacements as $from => $to) {
|
|||
|
$y = str_replace($from, $to, $y);
|
|||
|
}
|
|||
|
return $y;
|
|||
|
}
|
|||
|
);
|
|||
|
}
|
|||
|
if ($value === null) {
|
|||
|
return 'NULL';
|
|||
|
}
|
|||
|
else {
|
|||
|
$type = gettype($value);
|
|||
|
switch ($type) {
|
|||
|
case 'boolean': {
|
|||
|
return ($value ? 'TRUE' : 'FALSE');
|
|||
|
break;
|
|||
|
}
|
|||
|
case 'integer': {
|
|||
|
return sprintf('%d', $value);
|
|||
|
break;
|
|||
|
}
|
|||
|
case 'float':
|
|||
|
case 'double': {
|
|||
|
return sprintf('%.4f', $value);
|
|||
|
break;
|
|||
|
}
|
|||
|
case 'string': {
|
|||
|
return sprintf('\'%s\'', $escape($value));
|
|||
|
break;
|
|||
|
}
|
|||
|
case 'array': {
|
|||
|
return sprintf(
|
|||
|
'(%s)',
|
|||
|
implode(
|
|||
|
',',
|
|||
|
array_map(
|
|||
|
function ($element) : string {
|
|||
|
return format($element);
|
|||
|
},
|
|||
|
(
|
|||
|
empty($value)
|
|||
|
? ['___DUMMY_VALUE___']
|
|||
|
: $value
|
|||
|
)
|
|||
|
)
|
|||
|
)
|
|||
|
);
|
|||
|
}
|
|||
|
default: {
|
|||
|
throw (new \Exception(sprintf('unhandled type "%s" of value %s', $type, json_encode($value))));
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|