150 lines
2.5 KiB
PHP
150 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;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|