ulmus/src/Adapter/SQLite.php
2022-07-15 19:59:38 +00:00

193 lines
5.6 KiB
PHP

<?php
namespace Ulmus\Adapter;
use Ulmus\Common\PdoObject;
use Ulmus\Entity\Sqlite\Table;
use Ulmus\Exception\AdapterConfigurationException;
use Ulmus\Migration\FieldDefinition;
use Ulmus\{Repository, QueryBuilder, Ulmus};
class SQLite implements AdapterInterface {
use DefaultAdapterTrait;
const DSN_PREFIX = "sqlite";
public string $path;
public array $pragma;
public function __construct(
? string $path = null,
? array $pragma = null
) {
if ($path !== null) {
$this->path = $path;
}
if ($pragma !== null) {
$this->pragma = $pragma;
}
}
public function connect() : PdoObject
{
try {
$pdo = new PdoObject($this->buildDataSourceName(), null, null);
$pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
$pdo->setAttribute(\PDO::ATTR_EMULATE_PREPARES, false);
$pdo->setAttribute(\PDO::ATTR_DEFAULT_FETCH_MODE, \PDO::FETCH_ASSOC);
$this->exportFunctions($pdo);
}
catch(PDOException $ex){
throw $ex;
}
return $pdo;
}
public function buildDataSourceName() : string
{
$parts[] = $this->path;
return static::DSN_PREFIX . ":" . implode(';', $parts);
}
public function setup(array $configuration) : void
{
$this->path = $configuration['path'] ?? "";
$this->pragma = $configuration['pragma'] ?? [];
}
# https://sqlite.org/lang_keywords.html
public function escapeIdentifier(string $segment, int $type) : string
{
switch($type) {
case static::IDENTIFIER_DATABASE:
case static::IDENTIFIER_TABLE:
case static::IDENTIFIER_FIELD:
return '"' . trim(str_replace('"', '""', $segment), '"') . '"';
case static::IDENTIFIER_VALUE:
return "'$segment'";
}
}
public function defaultEngine(): ? string
{
return null;
}
public function databaseName() : string
{
$base = basename($this->path);
return substr($base, 0, strrpos($base, '.') ?: strlen($base));
}
public function schemaTable(string $databaseName, string $tableName) /* : ? object */
{
return Table::repository()->loadOneFromField(Table::field('tableName'), $tableName);
}
public function mapFieldType(FieldDefinition $field, bool $typeOnly = false) : string
{
$type = $field->type;
$length = $field->length;
if ( is_a($type, Entity\Field\Date::class, true) || is_a($type, Entity\Field\Time::class, true) || is_a($type, \DateTime::class, true) ) {
$type = "TEXT";
$length = strlen((string) $type);
}
else {
switch($type) {
case "bool":
$check = sprintf("CHECK (%s IN (0, 1))", $field->getColumnName());
case "bigint":
case "int":
$type = "INTEGER";
break;
case "array":
case "string":
$type = "TEXT";
$length = null;
break;
case "float":
$type = "REAL";
break;
default:
$type = "BLOB";
break;
}
}
return $typeOnly ? $type : $type . ( $length ? "($length" . ( isset($precision) ? ",$precision" : "" ) . ")" : "" );
}
public function writableValue(/* mixed */ $value) /*: mixed*/
{
switch (true) {
case is_object($value):
return Ulmus::convertObject($value);
case is_array($value):
return json_encode($value);
case is_bool($value):
return (int) $value;
}
return $value;
}
public function tableSyntax() : array
{
return [
'ai' => "AUTOINCREMENT",
'pk' => "PRIMARY KEY",
'unsigned' => "",
];
}
public function repositoryClass() : string
{
return Repository\SqliteRepository::class;
}
public function queryBuilderClass() : string
{
return QueryBuilder\SqliteQueryBuilder::class;
}
public function exportFunctions(PdoObject $pdo) : void
{
$pdo->sqliteCreateFunction('lcase', fn($string) => strtolower($string), 1);
$pdo->sqliteCreateFunction('ucase', fn($string) => strtoupper($string), 1);
$pdo->sqliteCreateFunction('left', fn($string, $length) => substr($string, 0, $length), 2);
$pdo->sqliteCreateFunction('right', fn($string, $length) => substr($string, -$length), 2);
$pdo->sqliteCreateFunction('strcmp', fn($s1, $s2) => strcmp($s1, $s2), 2);
$pdo->sqliteCreateFunction('lpad', fn($string, $length, $pad) => str_pad($string, $length, $pad, STR_PAD_LEFT), 3);
$pdo->sqliteCreateFunction('rpad', fn($string, $length, $pad) => str_pad($string, $length, $pad, STR_PAD_RIGHT), 3);
$pdo->sqliteCreateFunction('concat', fn(...$args) => implode('', $args), -1);
$pdo->sqliteCreateFunction('concat_ws', fn($separator, ...$args) => implode($separator, $args), -1);
$pdo->sqliteCreateFunction('find_in_set', function($string, $string_list) {
if ( $string === null || $string_list === null ) {
return null;
}
if ($string_list === "") {
return 0;
}
return (int) in_array($string, explode(',', $string_list));
}, 2);
}
}