193 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			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);
 | |
|     }
 | |
| }
 |