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); } }