modifs.mineures sans commentaires
This commit is contained in:
parent
2a46c12e08
commit
146461a184
@ -65,15 +65,29 @@ class CapacitorChannel {
|
||||
$this->created = false;
|
||||
$columnDefinitions = cl::withn(static::COLUMN_DEFINITIONS);
|
||||
$primaryKeys = cl::withn(static::PRIMARY_KEYS);
|
||||
if ($primaryKeys === null && $columnDefinitions !== null) {
|
||||
$migration = cl::withn(static::MIGRATION);
|
||||
if ($columnDefinitions !== null) {
|
||||
# mettre à jour la liste des clés primaires et des migrations
|
||||
$index = 0;
|
||||
foreach ($columnDefinitions as $col => $def) {
|
||||
if ($col === $index) {
|
||||
# si définition séquentielle, seules les définitions de clé
|
||||
# primaires sont supportées
|
||||
$index++;
|
||||
if (preg_match('/\bprimary\s+key\s+\((.+)\)/i', $def, $ms)) {
|
||||
$primaryKeys = preg_split('/\s*,\s*/', trim($ms[1]));
|
||||
}
|
||||
} elseif (is_array($def)) {
|
||||
# tableau: c'est une migration
|
||||
$def = implode(" ", $def);
|
||||
if ($def) {
|
||||
$migration["add_$col"] = "alter table $tableName add column $col $def";
|
||||
} else {
|
||||
$migration["drop_$col"] = "alter table $tableName drop column $col";
|
||||
}
|
||||
} elseif (is_scalar($def)) {
|
||||
# chaine: c'est une définition
|
||||
$def = strval($def);
|
||||
if (preg_match('/\bprimary\s+key\b/i', $def)) {
|
||||
$primaryKeys[] = $col;
|
||||
}
|
||||
@ -82,7 +96,7 @@ class CapacitorChannel {
|
||||
}
|
||||
$this->columnDefinitions = $columnDefinitions;
|
||||
$this->primaryKeys = $primaryKeys;
|
||||
$this->migration = cl::withn(static::MIGRATION);
|
||||
$this->migration = $migration;
|
||||
}
|
||||
|
||||
protected string $name;
|
||||
|
@ -47,7 +47,7 @@ abstract class CapacitorStorage {
|
||||
"modified_" => "serts",
|
||||
];
|
||||
|
||||
protected function ColumnDefinitions(CapacitorChannel $channel): array {
|
||||
protected function ColumnDefinitions(CapacitorChannel $channel, bool $ignoreMigrations=false): array {
|
||||
$definitions = [];
|
||||
if ($channel->getPrimaryKeys() === null) {
|
||||
$definitions[] = static::PRIMARY_KEY_DEFINITION;
|
||||
@ -69,9 +69,15 @@ abstract class CapacitorStorage {
|
||||
if ($col === $index) {
|
||||
$index++;
|
||||
$constraints[] = $def;
|
||||
} else {
|
||||
} elseif (is_array($def)) {
|
||||
# éventuellement, ignorer les migrations
|
||||
$def = implode(" ", $def);
|
||||
if ($def && !$ignoreMigrations) {
|
||||
$definitions[$col] = $def;
|
||||
}
|
||||
} elseif (is_scalar($def)) {
|
||||
$definitions[$col] = strval($def);
|
||||
}
|
||||
}
|
||||
return cl::merge($definitions, $constraints);
|
||||
}
|
||||
@ -145,7 +151,7 @@ abstract class CapacitorStorage {
|
||||
return [
|
||||
"create table if not exists",
|
||||
"table" => $channel->getTableName(),
|
||||
"cols" => $this->ColumnDefinitions($channel),
|
||||
"cols" => $this->ColumnDefinitions($channel, true),
|
||||
];
|
||||
}
|
||||
|
||||
@ -162,7 +168,37 @@ EOT;
|
||||
|
||||
abstract function _getMigration(CapacitorChannel $channel): _migration;
|
||||
|
||||
const CHANNELS_TABLE = "_channels";
|
||||
const CHANNELS_COLS = [
|
||||
"name" => "varchar primary key",
|
||||
"table_name" => "varchar",
|
||||
"class_name" => "varchar",
|
||||
];
|
||||
|
||||
protected function _createChannelsSql(): array {
|
||||
return [
|
||||
"create table if not exists",
|
||||
"table" => static::CHANNELS_TABLE,
|
||||
"cols" => static::CHANNELS_COLS,
|
||||
];
|
||||
}
|
||||
|
||||
protected function _addToChannelsSql(CapacitorChannel $channel): array {
|
||||
return [
|
||||
"insert",
|
||||
"into" => static::CHANNELS_TABLE,
|
||||
"values" => [
|
||||
"name" => $channel->getName(),
|
||||
"table_name" => $channel->getTableName(),
|
||||
"class_name" => get_class($channel),
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
protected function _afterCreate(CapacitorChannel $channel): void {
|
||||
$db = $this->db();
|
||||
$db->exec($this->_createChannelsSql());
|
||||
$db->exec($this->_addToChannelsSql($channel));
|
||||
}
|
||||
|
||||
protected function _create(CapacitorChannel $channel): void {
|
||||
@ -191,6 +227,22 @@ EOT;
|
||||
}
|
||||
|
||||
protected function _beforeReset(CapacitorChannel $channel): void {
|
||||
$db = $this->db;
|
||||
$name = $channel->getName();
|
||||
$db->exec([
|
||||
"delete",
|
||||
"from" => _migration::MIGRATION_TABLE,
|
||||
"where" => [
|
||||
"channel" => $name,
|
||||
],
|
||||
]);
|
||||
$db->exec([
|
||||
"delete",
|
||||
"from" => static::CHANNELS_TABLE,
|
||||
"where" => [
|
||||
"name" => $name,
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
/** supprimer le canal spécifié */
|
||||
|
@ -11,9 +11,8 @@ class _create extends _common {
|
||||
];
|
||||
|
||||
static function isa(string $sql): bool {
|
||||
//return preg_match("/^create(?:\s+table)?\b/i", $sql);
|
||||
#XXX implémentation minimale
|
||||
return preg_match("/^create\s+table\b/i", $sql);
|
||||
return preg_match("/^create(?:\s+table)?\b/i", $sql);
|
||||
}
|
||||
|
||||
static function parse(array $query, ?array &$bindings=null): string {
|
||||
|
@ -5,6 +5,14 @@ use nulib\db\IDatabase;
|
||||
use nulib\php\func;
|
||||
|
||||
abstract class _migration {
|
||||
const MIGRATION_TABLE = "_migration";
|
||||
const MIGRATION_COLS = [
|
||||
"channel" => "varchar not null",
|
||||
"name" => "varchar not null",
|
||||
"done" => "integer not null default 0",
|
||||
"primary key (channel, name)",
|
||||
];
|
||||
|
||||
const MIGRATION = null;
|
||||
|
||||
function __construct($migrations, string $channel="", ?IDatabase $db=null) {
|
||||
@ -25,21 +33,40 @@ abstract class _migration {
|
||||
/** @var callable[]|string[] */
|
||||
protected $migrations;
|
||||
|
||||
abstract function setup(): void;
|
||||
abstract function beforeMigrate(string $key): bool;
|
||||
abstract function afterMigrate(string $key): void;
|
||||
function ensureTable(): void {
|
||||
$this->db->exec([
|
||||
"create table if not exists",
|
||||
"table" => static::MIGRATION_TABLE,
|
||||
"cols" => static::MIGRATION_COLS,
|
||||
]);
|
||||
}
|
||||
|
||||
protected function isMigrated(string $name): bool {
|
||||
return boolval($this->db->get([
|
||||
"select 1",
|
||||
"from" => static::MIGRATION_TABLE,
|
||||
"where" => [
|
||||
"channel" => $this->channel,
|
||||
"name" => $name,
|
||||
"done" => 1,
|
||||
],
|
||||
]));
|
||||
}
|
||||
|
||||
abstract protected function setMigrated(string $name, bool $done): void;
|
||||
|
||||
function migrate(?IDatabase $db=null): void {
|
||||
$db = ($this->db ??= $db);
|
||||
$this->setup();
|
||||
foreach ($this->migrations as $key => $migration) {
|
||||
if (!$this->beforeMigrate($key)) continue;
|
||||
$this->ensureTable();
|
||||
foreach ($this->migrations as $name => $migration) {
|
||||
if ($this->isMigrated($name)) continue;
|
||||
$this->setMigrated($name, false);
|
||||
if (is_string($migration) || !func::is_callable($migration)) {
|
||||
$db->exec($migration);
|
||||
} else {
|
||||
func::with($migration)->bind($this, true)->invoke([$db, $key]);
|
||||
func::with($migration)->bind($this, true)->invoke([$db, $name]);
|
||||
}
|
||||
$this->afterMigrate($key);
|
||||
$this->setMigrated($name, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
<?php
|
||||
namespace nulib\db\mysql;
|
||||
|
||||
use nulib\cl;
|
||||
use nulib\db\CapacitorChannel;
|
||||
use nulib\db\CapacitorStorage;
|
||||
|
||||
@ -9,26 +10,44 @@ use nulib\db\CapacitorStorage;
|
||||
*/
|
||||
class MysqlStorage extends CapacitorStorage {
|
||||
function __construct($mysql) {
|
||||
$this->mysql = Mysql::with($mysql);
|
||||
$this->db = Mysql::with($mysql);
|
||||
}
|
||||
|
||||
protected Mysql $mysql;
|
||||
protected Mysql $db;
|
||||
|
||||
function db(): Mysql {
|
||||
return $this->mysql;
|
||||
return $this->db;
|
||||
}
|
||||
|
||||
const PRIMARY_KEY_DEFINITION = [
|
||||
"id_" => "integer primary key auto_increment",
|
||||
];
|
||||
|
||||
function _getMigration(CapacitorChannel $channel): _mysqlMigration {
|
||||
return new _mysqlMigration(cl::merge([
|
||||
$this->_createSql($channel),
|
||||
], $channel->getMigration()), $channel->getName());
|
||||
}
|
||||
|
||||
function _getCreateSql(CapacitorChannel $channel): string {
|
||||
$query = new _mysqlQuery($this->_createSql($channel));
|
||||
return self::format_sql($channel, $query->getSql());
|
||||
}
|
||||
|
||||
const CHANNELS_COLS = [
|
||||
"name" => "varchar(255) primary key",
|
||||
"table_name" => "varchar(64)",
|
||||
"class_name" => "varchar(255)",
|
||||
];
|
||||
|
||||
protected function _addToChannelsSql(CapacitorChannel $channel): array {
|
||||
return cl::merge(parent::_addToChannelsSql($channel), [
|
||||
"suffix" => "on duplicate key update name = name",
|
||||
]);
|
||||
}
|
||||
|
||||
function _exists(CapacitorChannel $channel): bool {
|
||||
$mysql = $this->mysql;
|
||||
$mysql = $this->db;
|
||||
$tableName = $mysql->get([
|
||||
"select table_name from information_schema.tables",
|
||||
"where" => [
|
||||
@ -40,6 +59,6 @@ class MysqlStorage extends CapacitorStorage {
|
||||
}
|
||||
|
||||
function close(): void {
|
||||
$this->mysql->close();
|
||||
$this->db->close();
|
||||
}
|
||||
}
|
||||
|
31
php/src/db/mysql/_mysqlMigration.php
Normal file
31
php/src/db/mysql/_mysqlMigration.php
Normal file
@ -0,0 +1,31 @@
|
||||
<?php
|
||||
namespace nulib\db\mysql;
|
||||
|
||||
use nulib\db\_private\_migration;
|
||||
|
||||
class _mysqlMigration extends _migration {
|
||||
const MIGRATION_COLS = [
|
||||
"channel" => "varchar(64) not null",
|
||||
"name" => "varchar(64) not null",
|
||||
"done" => "integer not null default 0",
|
||||
"primary key (channel, name)",
|
||||
];
|
||||
|
||||
static function with($migration): self {
|
||||
if ($migration instanceof self) return $migration;
|
||||
else return new static($migration);
|
||||
}
|
||||
|
||||
protected function setMigrated(string $name, bool $done): void {
|
||||
$this->db->exec([
|
||||
"insert",
|
||||
"into" => static::MIGRATION_TABLE,
|
||||
"values" => [
|
||||
"channel" => $this->channel,
|
||||
"name" => $name,
|
||||
"done" => $done? 1: 0,
|
||||
],
|
||||
"suffix" => "on duplicate key update done = :done",
|
||||
]);
|
||||
}
|
||||
}
|
@ -4,4 +4,5 @@ namespace nulib\db\mysql;
|
||||
use nulib\db\pdo\_pdoQuery;
|
||||
|
||||
class _mysqlQuery extends _pdoQuery {
|
||||
const DEBUG_QUERIES = false;
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
<?php
|
||||
namespace nulib\db\pgsql;
|
||||
|
||||
use nulib\cl;
|
||||
use nulib\db\CapacitorChannel;
|
||||
use nulib\db\CapacitorStorage;
|
||||
|
||||
@ -10,54 +11,33 @@ class PgsqlStorage extends CapacitorStorage {
|
||||
const SERTS_DEFINITION = "timestamp";
|
||||
|
||||
function __construct($pgsql) {
|
||||
$this->pgsql = Pgsql::with($pgsql);
|
||||
$this->db = Pgsql::with($pgsql);
|
||||
}
|
||||
|
||||
protected Pgsql $pgsql;
|
||||
protected Pgsql $db;
|
||||
|
||||
function db(): Pgsql {
|
||||
return $this->pgsql;
|
||||
return $this->db;
|
||||
}
|
||||
|
||||
const PRIMARY_KEY_DEFINITION = [
|
||||
"id_" => "serial primary key",
|
||||
];
|
||||
|
||||
function _getMigration(CapacitorChannel $channel): _pgsqlMigration {
|
||||
return new _pgsqlMigration(cl::merge([
|
||||
$this->_createSql($channel),
|
||||
], $channel->getMigration()), $channel->getName());
|
||||
}
|
||||
|
||||
function _getCreateSql(CapacitorChannel $channel): string {
|
||||
$query = new _pgsqlQuery($this->_createSql($channel));
|
||||
return self::format_sql($channel, $query->getSql());
|
||||
}
|
||||
|
||||
protected function _afterCreate(CapacitorChannel $channel): void {
|
||||
$db = $this->pgsql;
|
||||
$db->exec([
|
||||
"create table if not exists",
|
||||
"table" => "_channels",
|
||||
"cols" => [
|
||||
"name" => "varchar primary key",
|
||||
"table_name" => "varchar",
|
||||
"class" => "varchar",
|
||||
],
|
||||
]);
|
||||
$db->exec([
|
||||
"insert",
|
||||
"into" => "_channels",
|
||||
"values" => [
|
||||
"name" => $channel->getName(),
|
||||
"table_name" => $channel->getTableName(),
|
||||
"class" => get_class($channel),
|
||||
],
|
||||
"suffix" => "on conflict (name) do nothing",
|
||||
]);
|
||||
}
|
||||
|
||||
protected function _beforeReset(CapacitorChannel $channel): void {
|
||||
$this->pgsql->exec([
|
||||
"delete",
|
||||
"from" => "_channels",
|
||||
"where" => [
|
||||
"name" => $channel->getName(),
|
||||
],
|
||||
protected function _addToChannelsSql(CapacitorChannel $channel): array {
|
||||
return cl::merge(parent::_addToChannelsSql($channel), [
|
||||
"suffix" => "on conflict do nothing",
|
||||
]);
|
||||
}
|
||||
|
||||
@ -69,7 +49,7 @@ class PgsqlStorage extends CapacitorStorage {
|
||||
} else {
|
||||
$schemaName = "public";
|
||||
}
|
||||
return null !== $this->pgsql->get([
|
||||
return null !== $this->db->get([
|
||||
"select tablename from pg_tables",
|
||||
"where" => [
|
||||
"schemaname" => $schemaName,
|
||||
@ -79,6 +59,6 @@ class PgsqlStorage extends CapacitorStorage {
|
||||
}
|
||||
|
||||
function close(): void {
|
||||
$this->pgsql->close();
|
||||
$this->db->close();
|
||||
}
|
||||
}
|
||||
|
24
php/src/db/pgsql/_pgsqlMigration.php
Normal file
24
php/src/db/pgsql/_pgsqlMigration.php
Normal file
@ -0,0 +1,24 @@
|
||||
<?php
|
||||
namespace nulib\db\pgsql;
|
||||
|
||||
use nulib\db\_private\_migration;
|
||||
|
||||
class _pgsqlMigration extends _migration {
|
||||
static function with($migration): self {
|
||||
if ($migration instanceof self) return $migration;
|
||||
else return new static($migration);
|
||||
}
|
||||
|
||||
protected function setMigrated(string $name, bool $done): void {
|
||||
$this->db->exec([
|
||||
"insert",
|
||||
"into" => static::MIGRATION_TABLE,
|
||||
"values" => [
|
||||
"channel" => $this->channel,
|
||||
"name" => $name,
|
||||
"done" => $done? 1: 0,
|
||||
],
|
||||
"suffix" => "on conflict (channel, name) do update set done = :done",
|
||||
]);
|
||||
}
|
||||
}
|
@ -10,13 +10,13 @@ use nulib\db\CapacitorStorage;
|
||||
*/
|
||||
class SqliteStorage extends CapacitorStorage {
|
||||
function __construct($sqlite) {
|
||||
$this->sqlite = Sqlite::with($sqlite);
|
||||
$this->db = Sqlite::with($sqlite);
|
||||
}
|
||||
|
||||
protected Sqlite $sqlite;
|
||||
protected Sqlite $db;
|
||||
|
||||
function db(): Sqlite {
|
||||
return $this->sqlite;
|
||||
return $this->db;
|
||||
}
|
||||
|
||||
const PRIMARY_KEY_DEFINITION = [
|
||||
@ -35,7 +35,7 @@ class SqliteStorage extends CapacitorStorage {
|
||||
}
|
||||
|
||||
function tableExists(string $tableName): bool {
|
||||
$name = $this->sqlite->get([
|
||||
$name = $this->db->get([
|
||||
# depuis la version 3.33.0 le nom officiel de la table est sqlite_schema,
|
||||
# mais le nom sqlite_master est toujours valable pour le moment
|
||||
"select name from sqlite_master ",
|
||||
@ -45,63 +45,38 @@ class SqliteStorage extends CapacitorStorage {
|
||||
}
|
||||
|
||||
function channelExists(string $name): bool {
|
||||
$name = $this->sqlite->get([
|
||||
"select name from _channels",
|
||||
return null !== $this->db->get([
|
||||
"select name",
|
||||
"from" => static::CHANNELS_TABLE,
|
||||
"where" => ["name" => $name],
|
||||
]);
|
||||
return $name !== null;
|
||||
}
|
||||
|
||||
protected function _addToChannelsSql(CapacitorChannel $channel): array {
|
||||
return cl::merge(parent::_createChannelsSql(), [
|
||||
"suffix" => "on conflict ignore",
|
||||
]);
|
||||
}
|
||||
|
||||
protected function _afterCreate(CapacitorChannel $channel): void {
|
||||
$sqlite = $this->sqlite;
|
||||
if (!$this->tableExists("_channels")) {
|
||||
$db = $this->db;
|
||||
if (!$this->tableExists(static::CHANNELS_TABLE)) {
|
||||
# ne pas créer si la table existe déjà, pour éviter d'avoir besoin d'un
|
||||
# verrou en écriture
|
||||
$sqlite->exec([
|
||||
"create table if not exists _channels",
|
||||
"cols" => [
|
||||
"name" => "varchar primary key",
|
||||
"table_name" => "varchar",
|
||||
"class" => "varchar",
|
||||
],
|
||||
]);
|
||||
$db->exec($this->_createChannelsSql());
|
||||
}
|
||||
if (!$this->channelExists($channel->getName())) {
|
||||
# ne pas insérer si la ligne existe déjà, pour éviter d'avoir besoin d'un
|
||||
# verrou en écriture
|
||||
$sqlite->exec([
|
||||
"insert into _channels",
|
||||
"values" => [
|
||||
"name" => $channel->getName(),
|
||||
"table_name" => $channel->getTableName(),
|
||||
"class" => get_class($channel),
|
||||
],
|
||||
"suffix" => "on conflict do nothing",
|
||||
]);
|
||||
$this->_addToChannelsSql($channel);
|
||||
}
|
||||
}
|
||||
|
||||
protected function _beforeReset(CapacitorChannel $channel): void {
|
||||
$sqlite = $this->sqlite;
|
||||
$sqlite->exec([
|
||||
"delete from _migration",
|
||||
"where" => [
|
||||
"channel" => $channel->getName(),
|
||||
],
|
||||
]);
|
||||
$sqlite->exec([
|
||||
"delete from _channels",
|
||||
"where" => [
|
||||
"name" => $channel->getName(),
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
function _exists(CapacitorChannel $channel): bool {
|
||||
return $this->tableExists($channel->getTableName());
|
||||
}
|
||||
|
||||
function close(): void {
|
||||
$this->sqlite->close();
|
||||
$this->db->close();
|
||||
}
|
||||
}
|
||||
|
@ -9,48 +9,14 @@ class _sqliteMigration extends _migration {
|
||||
else return new static($migration);
|
||||
}
|
||||
|
||||
function setup(): void {
|
||||
protected function setMigrated(string $name, bool $done): void {
|
||||
$this->db->exec([
|
||||
"create table if not exists _migration",
|
||||
"cols" => [
|
||||
"channel" => "varchar not null",
|
||||
"key" => "varchar not null",
|
||||
"done" => "integer not null default 0",
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
function beforeMigrate(string $key): bool {
|
||||
$db = $this->db;
|
||||
$migrated = $db->get([
|
||||
"select 1 from _migration",
|
||||
"where" => [
|
||||
"channel" => $this->channel,
|
||||
"key" => $key,
|
||||
"done" => 1,
|
||||
],
|
||||
]);
|
||||
if ($migrated) return false;
|
||||
$db->exec([
|
||||
"insert or replace into _migration",
|
||||
"insert or replace",
|
||||
"into" => static::MIGRATION_TABLE,
|
||||
"values" => [
|
||||
"channel" => $this->channel,
|
||||
"key" => $key,
|
||||
"done" => 0,
|
||||
],
|
||||
]);
|
||||
return true;
|
||||
}
|
||||
|
||||
function afterMigrate(string $key): void {
|
||||
$this->db->exec([
|
||||
"update _migration",
|
||||
"values" => [
|
||||
"done" => 1,
|
||||
],
|
||||
"where" => [
|
||||
"channel" => $this->channel,
|
||||
"key" => $key,
|
||||
"name" => $name,
|
||||
"done" => $done? 1: 0,
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user