- Merging
This commit is contained in:
		
						commit
						5a5d326d70
					
				| @ -39,7 +39,7 @@ class MsSQL implements AdapterInterface, MigrateInterface, SqlAdapterInterface { | ||||
|     public string $database; | ||||
|      | ||||
|     public string $username; | ||||
|      | ||||
| 
 | ||||
|     public string $password; | ||||
|      | ||||
|     public string $traceFile; | ||||
| @ -51,7 +51,9 @@ class MsSQL implements AdapterInterface, MigrateInterface, SqlAdapterInterface { | ||||
|     public function __construct( | ||||
|         ?string $server = null, | ||||
|         ?string $database = null, | ||||
|         #[\SensitiveParameter]
 | ||||
|         ?string $username = null, | ||||
|         #[\SensitiveParameter]
 | ||||
|         ?string $password = null, | ||||
|         ?int $port = null | ||||
|     ) { | ||||
|  | ||||
| @ -38,7 +38,9 @@ class MySQL implements AdapterInterface, MigrateInterface, SqlAdapterInterface { | ||||
|     public function __construct( | ||||
|         ?string $hostname = null, | ||||
|         ?string $database = null, | ||||
|         #[\SensitiveParameter]
 | ||||
|         ?string $username = null, | ||||
|         #[\SensitiveParameter]
 | ||||
|         ?string $password = null, | ||||
|         ?int $port = null, | ||||
|         ?string $charset = null | ||||
|  | ||||
| @ -3,6 +3,7 @@ | ||||
| namespace Ulmus\Adapter; | ||||
| 
 | ||||
| use Ulmus\Migration\FieldDefinition; | ||||
| use Ulmus\Entity; | ||||
| 
 | ||||
| class SqlFieldMapper | ||||
| { | ||||
| @ -42,7 +43,7 @@ class SqlFieldMapper | ||||
|         switch($type) { | ||||
|             case "bool": | ||||
|                 $this->type = "TINYINT"; | ||||
|                 $length = 1; | ||||
|                 $this->length = 1; | ||||
|                 break; | ||||
| 
 | ||||
|             case "array": | ||||
| @ -52,6 +53,7 @@ class SqlFieldMapper | ||||
|             case "string": | ||||
|                 if ($length && $length <= 255) { | ||||
|                     $this->type = "VARCHAR"; | ||||
|                     $this->length = $length; | ||||
|                     break; | ||||
|                 } | ||||
|                 elseif (! $length || ( $length <= 65535 ) ) { | ||||
| @ -74,11 +76,13 @@ class SqlFieldMapper | ||||
| 
 | ||||
|             case "float": | ||||
|                 $this->type = "DOUBLE"; | ||||
|                 break; | ||||
| 
 | ||||
|             default: | ||||
|                 $this->type = strtoupper($type); | ||||
|                 break; | ||||
|                 if ($length) { | ||||
|                     $this->length = $length; | ||||
|                 } | ||||
| 
 | ||||
|                 $this->type ??= strtoupper($type); | ||||
|         } | ||||
| 
 | ||||
|         $this->postProcess(); | ||||
|  | ||||
| @ -13,7 +13,7 @@ class OrWhere extends Where { | ||||
|         public string $operator = Query\Where::OPERATOR_EQUAL, | ||||
|         public string $condition = Query\Where::CONDITION_OR, | ||||
|         public string|\Stringable|array|null $fieldValue = null, | ||||
|         public null|array $generateValue = null, | ||||
|         public null|array|\Closure $generateValue = null, | ||||
|     ) { | ||||
|         parent::__construct($field, $value, $operator, $condition, $fieldValue, $generateValue); | ||||
|     } | ||||
|  | ||||
							
								
								
									
										42
									
								
								src/Attribute/Property/Relation/ManyToMany.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								src/Attribute/Property/Relation/ManyToMany.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,42 @@ | ||||
| <?php | ||||
| 
 | ||||
| namespace Ulmus\Attribute\Property\Relation; | ||||
| 
 | ||||
| use Ulmus\Attribute\Property\Relation; | ||||
| 
 | ||||
| #[\Attribute(\Attribute::TARGET_PROPERTY)]
 | ||||
| class ManyToMany extends Relation | ||||
| { | ||||
|     public function __construct( | ||||
|         public \Stringable|string|array $key = "", | ||||
|         public null|\Closure|array $generateKey = null, | ||||
|         public null|\Stringable|string|array $foreignKey = null, | ||||
|         public null|\Stringable|string|array $foreignField = null, | ||||
|         public array $foreignKeys = [], | ||||
|         public null|string $bridge = null, | ||||
|         public null|\Stringable|string|array $bridgeKey = null, | ||||
|         public null|\Stringable|string|array $bridgeField = null, | ||||
|         public null|\Stringable|string|array $bridgeForeignKey = null, | ||||
|         public null|\Stringable|string|array $field = null, | ||||
|         public null|string $entity = null, | ||||
|         public null|string $join = null, | ||||
|         public null|string $function = null, | ||||
|     ) { | ||||
|         parent::__construct( | ||||
|             RelationTypeEnum::manyToMany, | ||||
|             $this->key, | ||||
|             $this->generateKey, | ||||
|             $this->foreignKey, | ||||
|             $this->foreignField, | ||||
|             $this->foreignKeys, | ||||
|             $this->bridge, | ||||
|             $this->bridgeKey, | ||||
|             $this->bridgeField, | ||||
|             $this->bridgeForeignKey, | ||||
|             $this->field, | ||||
|             $this->entity, | ||||
|             $this->join, | ||||
|             $this->function, | ||||
|         ); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										42
									
								
								src/Attribute/Property/Relation/OneToMany.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								src/Attribute/Property/Relation/OneToMany.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,42 @@ | ||||
| <?php | ||||
| 
 | ||||
| namespace Ulmus\Attribute\Property\Relation; | ||||
| 
 | ||||
| use Ulmus\Attribute\Property\Relation; | ||||
| 
 | ||||
| #[\Attribute(\Attribute::TARGET_PROPERTY)]
 | ||||
| class OneToMany extends Relation | ||||
| { | ||||
|     public function __construct( | ||||
|         public \Stringable|string|array $key = "", | ||||
|         public null|\Closure|array $generateKey = null, | ||||
|         public null|\Stringable|string|array $foreignKey = null, | ||||
|         public null|\Stringable|string|array $foreignField = null, | ||||
|         public array $foreignKeys = [], | ||||
|         public null|string $bridge = null, | ||||
|         public null|\Stringable|string|array $bridgeKey = null, | ||||
|         public null|\Stringable|string|array $bridgeField = null, | ||||
|         public null|\Stringable|string|array $bridgeForeignKey = null, | ||||
|         public null|\Stringable|string|array $field = null, | ||||
|         public null|string $entity = null, | ||||
|         public null|string $join = null, | ||||
|         public null|string $function = null, | ||||
|     ) { | ||||
|         parent::__construct( | ||||
|             RelationTypeEnum::oneToMany, | ||||
|             $this->key, | ||||
|             $this->generateKey, | ||||
|             $this->foreignKey, | ||||
|             $this->foreignField, | ||||
|             $this->foreignKeys, | ||||
|             $this->bridge, | ||||
|             $this->bridgeKey, | ||||
|             $this->bridgeField, | ||||
|             $this->bridgeForeignKey, | ||||
|             $this->field, | ||||
|             $this->entity, | ||||
|             $this->join, | ||||
|             $this->function, | ||||
|         ); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										42
									
								
								src/Attribute/Property/Relation/OneToOne.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								src/Attribute/Property/Relation/OneToOne.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,42 @@ | ||||
| <?php | ||||
| 
 | ||||
| namespace Ulmus\Attribute\Property\Relation; | ||||
| 
 | ||||
| use Ulmus\Attribute\Property\Relation; | ||||
| 
 | ||||
| #[\Attribute(\Attribute::TARGET_PROPERTY)]
 | ||||
| class OneToOne extends Relation | ||||
| { | ||||
|     public function __construct( | ||||
|         public \Stringable|string|array $key = "", | ||||
|         public null|\Closure|array $generateKey = null, | ||||
|         public null|\Stringable|string|array $foreignKey = null, | ||||
|         public null|\Stringable|string|array $foreignField = null, | ||||
|         public array $foreignKeys = [], | ||||
|         public null|string $bridge = null, | ||||
|         public null|\Stringable|string|array $bridgeKey = null, | ||||
|         public null|\Stringable|string|array $bridgeField = null, | ||||
|         public null|\Stringable|string|array $bridgeForeignKey = null, | ||||
|         public null|\Stringable|string|array $field = null, | ||||
|         public null|string $entity = null, | ||||
|         public null|string $join = null, | ||||
|         public null|string $function = null, | ||||
|     ) { | ||||
|         parent::__construct( | ||||
|             RelationTypeEnum::oneToOne, | ||||
|             $this->key, | ||||
|             $this->generateKey, | ||||
|             $this->foreignKey, | ||||
|             $this->foreignField, | ||||
|             $this->foreignKeys, | ||||
|             $this->bridge, | ||||
|             $this->bridgeKey, | ||||
|             $this->bridgeField, | ||||
|             $this->bridgeForeignKey, | ||||
|             $this->field, | ||||
|             $this->entity, | ||||
|             $this->join, | ||||
|             $this->function, | ||||
|         ); | ||||
|     } | ||||
| } | ||||
| @ -13,7 +13,7 @@ class Where { | ||||
|         public string $operator = Query\Where::OPERATOR_EQUAL, | ||||
|         public string $condition = Query\Where::CONDITION_AND, | ||||
|         public string|\Stringable|array|null $fieldValue = null, | ||||
|         public null|array $generateValue = null, | ||||
|         public null|array|\Closure $generateValue = null, | ||||
|     ) { | ||||
|         $this->field = Attribute::handleArrayField($field); | ||||
|         $this->fieldValue = Attribute::handleArrayField($fieldValue); | ||||
| @ -29,6 +29,9 @@ class Where { | ||||
|                 throw new \Exception(sprintf("Could not generate value from non-instanciated entity for field %s.", (string) $this->field)); | ||||
|             } | ||||
|         } | ||||
|         elseif ($this->fieldValue && $entity) { | ||||
|             throw new \Exception(sprintf("Field value, from %s, could not be included in query since the entity is already loaded; it is meant to be used with a OneToOne relation loaded within a join.", (string) $this->fieldValue)); | ||||
|         } | ||||
| 
 | ||||
|         return $this->fieldValue ?? $this->value; | ||||
|     } | ||||
|  | ||||
							
								
								
									
										22
									
								
								src/Cache/CacheEventTrait.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								src/Cache/CacheEventTrait.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,22 @@ | ||||
| <?php | ||||
| 
 | ||||
| namespace Ulmus\Cache; | ||||
| 
 | ||||
| use Psr\SimpleCache\CacheInterface; | ||||
| 
 | ||||
| trait CacheEventTrait | ||||
| { | ||||
|     public function __construct( | ||||
|         protected CacheInterface $cache, | ||||
|         protected string $cacheKey, | ||||
|     ) {} | ||||
| 
 | ||||
|     public function purgeCache() : void | ||||
|     { | ||||
|         $keys = $this->cache->get($this->cacheKey); | ||||
| 
 | ||||
|         if ( $keys && is_iterable($keys) ) { | ||||
|             $this->cache->deleteMultiple(array_map(fn($e) => sprintf("%s:%s:", $this->cacheKey, $e), $keys)); | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										117
									
								
								src/CacheTrait.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										117
									
								
								src/CacheTrait.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,117 @@ | ||||
| <?php | ||||
| 
 | ||||
| namespace Ulmus; | ||||
| 
 | ||||
| use Psr\SimpleCache\CacheInterface; | ||||
| use Ulmus\Entity\EntityInterface; | ||||
| use Ulmus\QueryBuilder\QueryBuilderInterface; | ||||
| use Ulmus\Repository\RepositoryInterface; | ||||
| 
 | ||||
| trait CacheTrait | ||||
| { | ||||
|     protected CacheInterface $cache; | ||||
| 
 | ||||
|     public function attachCachingObject(CacheInterface $cache) : self | ||||
|     { | ||||
|         $cacheKey = ""; | ||||
|         $this->cache = $cache; | ||||
| 
 | ||||
|         # Reading from cache
 | ||||
|         $this->eventRegister(new class($cacheKey) implements Event\Repository\CollectionFromQueryDatasetInterface { | ||||
| 
 | ||||
|             public function __construct( | ||||
|                 protected string & $cacheKey | ||||
|             ) {} | ||||
| 
 | ||||
|             public function execute(RepositoryInterface $repository, array &$data): void | ||||
|             { | ||||
|                 $this->cacheKey = $repository->queryBuilder->hashSerializedQuery(); | ||||
|                 $data = $repository->getFromCache( $this->cacheKey) ?: []; | ||||
|             } | ||||
|         }); | ||||
| 
 | ||||
|         # Setting to cache
 | ||||
|         $this->eventRegister(new class($cacheKey) implements Event\Repository\CollectionFromQueryInterface { | ||||
|             public function __construct( | ||||
|                 protected string & $cacheKey | ||||
|             ) {} | ||||
| 
 | ||||
| 
 | ||||
|             public function execute(RepositoryInterface $repository, EntityCollection $collection): EntityCollection | ||||
|             { | ||||
|                 $repository->setToCache( $this->cacheKey, $collection->map(fn(EntityInterface $e) => $e->entityGetDataset(false, true))); | ||||
|                 $this->cacheKey = ""; | ||||
| 
 | ||||
|                 return $collection; | ||||
|             } | ||||
|         }); | ||||
| 
 | ||||
|         $this->eventRegister(new class($this->cache, $this->entityCacheKey()) implements Event\Query\Insert { | ||||
|             use Cache\CacheEventTrait; | ||||
| 
 | ||||
|             public function execute(RepositoryInterface $repository, object|array $entity, ?array $dataset = null, bool $replace = false): void | ||||
|             { | ||||
|                 $this->purgeCache(); | ||||
|             } | ||||
|         }); | ||||
| 
 | ||||
|         # Cache invalidation
 | ||||
|         $this->eventRegister(new class($this->cache, $this->entityCacheKey()) implements Event\Query\Update { | ||||
|             use Cache\CacheEventTrait; | ||||
| 
 | ||||
|             public function execute(RepositoryInterface $repository, object|array $entity, ?array $dataset = null, bool $replace = false): void | ||||
|             { | ||||
|                 $this->purgeCache(); | ||||
|             } | ||||
|         }); | ||||
| 
 | ||||
|         $this->eventRegister(new class($this->cache, $this->entityCacheKey()) implements  Event\Query\Delete { | ||||
|             use Cache\CacheEventTrait; | ||||
| 
 | ||||
|             public function execute(RepositoryInterface $repository, EntityInterface $entity): void | ||||
|             { | ||||
|                 $this->purgeCache(); | ||||
|             } | ||||
|         }); | ||||
| 
 | ||||
|         $this->eventRegister(new class($this->cache, $this->entityCacheKey()) implements Event\Query\Truncate { | ||||
|             use Cache\CacheEventTrait; | ||||
| 
 | ||||
|             public function execute(RepositoryInterface $repository, ?string $table = null, ?string $alias = null, ?string $schema = null): void | ||||
|             { | ||||
|                 $this->purgeCache(); | ||||
|             } | ||||
|         }); | ||||
| 
 | ||||
|         return $this; | ||||
|     } | ||||
| 
 | ||||
|     protected function entityCacheKey() : string | ||||
|     { | ||||
|         return sprintf("%s.%s", $this->entityResolver->databaseName(), $this->entityResolver->tableName()); | ||||
|     } | ||||
| 
 | ||||
|     public function getFromCache(string $key) : mixed | ||||
|     { | ||||
|         $keys = $this->cache->get($this->entityCacheKey(), []); | ||||
| 
 | ||||
|         if (in_array($key, $keys)) { | ||||
|             return $this->cache->get(sprintf("%s:%s:", $this->entityCacheKey(), $key)); | ||||
|         } | ||||
| 
 | ||||
|         return null; | ||||
|     } | ||||
| 
 | ||||
|     public function setToCache(string $key, mixed $value) : void | ||||
|     { | ||||
|         $keys = $this->cache->get($this->entityCacheKey(), []); | ||||
| 
 | ||||
|         if (! in_array($key, $keys)) { | ||||
|             $keys[] = $key; | ||||
| 
 | ||||
|             $this->cache->set($this->entityCacheKey(), $keys); | ||||
|         } | ||||
| 
 | ||||
|         $this->cache->set(sprintf("%s:%s:", $this->entityCacheKey(), $key), $value); | ||||
|     } | ||||
| } | ||||
| @ -49,7 +49,12 @@ class PdoObject extends PDO { | ||||
|             if (false !== ( $statement = $this->prepare($sql) )) { | ||||
|                 return $this->execute($statement, $parameters, true); | ||||
|             } | ||||
|         }  | ||||
|         } | ||||
|         catch(\PDOException $pdo) { | ||||
|             if ( substr($pdo->getMessage(), 0, 30) !== 'There is no active transaction' ) { | ||||
|                 throw $pdo; | ||||
|             } | ||||
|         } | ||||
|         catch (\Throwable $e) { | ||||
|             throw new \PdoException($e->getMessage() . " `$sql` with data:" . json_encode($parameters)); | ||||
|         } | ||||
|  | ||||
| @ -2,26 +2,23 @@ | ||||
| 
 | ||||
| namespace Ulmus; | ||||
| 
 | ||||
| use Psr\SimpleCache\CacheInterface; | ||||
| use Ulmus\Adapter\AdapterInterface; | ||||
| 
 | ||||
| use Ulmus\Common\PdoObject; | ||||
| 
 | ||||
| class ConnectionAdapter | ||||
| { | ||||
|     public string $name; | ||||
| 
 | ||||
|     public array $configuration; | ||||
| 
 | ||||
|     protected AdapterInterface $adapter; | ||||
| 
 | ||||
|     protected PdoObject $pdo; | ||||
| 
 | ||||
|     public function __construct(string $name = "default", array $configuration = [], bool $default = false) | ||||
|     { | ||||
|         $this->name = $name; | ||||
|          | ||||
|         $this->configuration = $configuration; | ||||
| 
 | ||||
|     public function __construct( | ||||
|         public string $name = "default", | ||||
|         protected array $configuration = [], | ||||
|         public bool $default = false, | ||||
|         public ? CacheInterface $cacheObject = null | ||||
|     ) { | ||||
|         Ulmus::registerAdapter($this, $default); | ||||
|     } | ||||
| 
 | ||||
|  | ||||
| @ -5,7 +5,7 @@ namespace Ulmus\Entity\InformationSchema; | ||||
| use Ulmus\EntityCollection, | ||||
|     Ulmus\Entity\Field\Datetime; | ||||
| 
 | ||||
| use Ulmus\{Attribute\Obj\Table as TableObj}; | ||||
| use Ulmus\{Attribute\Obj\Table as TableObj, Entity\EntityInterface}; | ||||
| use Ulmus\Attribute\Property\{Field, Filter, FilterJoin, Relation, Join, Virtual, Where}; | ||||
| 
 | ||||
| #[TableObj(name: "tables", database: "information_schema")]
 | ||||
| @ -83,6 +83,12 @@ class Table | ||||
|     public ? string $temporary; | ||||
| 
 | ||||
|     #[Relation(type: "oneToMany", key: "name", foreignKey: [ Column::class, 'tableName' ], entity: Column::class)]
 | ||||
|     #[Where('TABLE_SCHEMA', fieldValue: [ Column::class, 'tableSchema' ])]
 | ||||
|     #[Where(field: 'TABLE_SCHEMA', generateValue: [ Table::class, 'getSchema' ])]
 | ||||
|     public EntityCollection $columns; | ||||
| 
 | ||||
|     # Awaiting PHP 8.5 https://wiki.php.net/rfc/closures_in_const_expr
 | ||||
|     public static function getSchema(Table $entity) : string | ||||
|     { | ||||
|         return $entity->schema; | ||||
|     } | ||||
| } | ||||
| @ -12,6 +12,6 @@ use Ulmus\Attribute\Property\{Field, Filter, FilterJoin, Relation, Join, Virtual | ||||
| class Table extends \Ulmus\Entity\InformationSchema\Table | ||||
| { | ||||
|     #[Relation(type: "oneToMany", key: "name", foreignKey: [ Column::class, 'tableName' ], entity: Column::class)]
 | ||||
|     #[Where('TABLE_SCHEMA', fieldValue: [ Column::class, 'tableSchema' ])]
 | ||||
|     #[Where('TABLE_SCHEMA', generateValue: [ Table::class, 'getSchema' ])]
 | ||||
|     public EntityCollection $columns; | ||||
| } | ||||
| @ -235,7 +235,7 @@ trait EntityTrait { | ||||
|     #[Ignore]
 | ||||
|     public static function field($name, null|string|false $alias = Repository::DEFAULT_ALIAS) : EntityField | ||||
|     { | ||||
|         $default = ( $alias === false ? '' : Repository::DEFAULT_ALIAS ); # bw compatibility, to be deprecated
 | ||||
|         $default = ( $alias === false ? '' : static::repository()::DEFAULT_ALIAS ); # bw compatibility, to be deprecated
 | ||||
| 
 | ||||
|         $alias = $alias ? Ulmus::repository(static::class)->adapter->adapter()->escapeIdentifier($alias, Adapter\AdapterInterface::IDENTIFIER_FIELD) : $default; | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										9
									
								
								src/Event/Query/Alter.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/Event/Query/Alter.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,9 @@ | ||||
| <?php | ||||
| 
 | ||||
| namespace Ulmus\Event\Query; | ||||
| 
 | ||||
| use Ulmus\Repository\RepositoryInterface; | ||||
| 
 | ||||
| interface Alter { | ||||
|     public function execute(RepositoryInterface $repository, array $fields) : void; | ||||
| } | ||||
							
								
								
									
										9
									
								
								src/Event/Query/Create.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/Event/Query/Create.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,9 @@ | ||||
| <?php | ||||
| 
 | ||||
| namespace Ulmus\Event\Query; | ||||
| 
 | ||||
| use Ulmus\Repository\RepositoryInterface; | ||||
| 
 | ||||
| interface Create { | ||||
|     public function execute(RepositoryInterface $repository) : void; | ||||
| } | ||||
							
								
								
									
										10
									
								
								src/Event/Query/Delete.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								src/Event/Query/Delete.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,10 @@ | ||||
| <?php | ||||
| 
 | ||||
| namespace Ulmus\Event\Query; | ||||
| 
 | ||||
| use Ulmus\Entity\EntityInterface; | ||||
| use Ulmus\Repository\RepositoryInterface; | ||||
| 
 | ||||
| interface Delete { | ||||
|     public function execute(RepositoryInterface $repository, EntityInterface $entity) : void; | ||||
| } | ||||
							
								
								
									
										9
									
								
								src/Event/Query/Insert.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/Event/Query/Insert.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,9 @@ | ||||
| <?php | ||||
| 
 | ||||
| namespace Ulmus\Event\Query; | ||||
| 
 | ||||
| use Ulmus\Repository\RepositoryInterface; | ||||
| 
 | ||||
| interface Insert { | ||||
|     public function execute(RepositoryInterface $repository, object|array $entity, ? array $dataset = null, bool $replace = false) : void; | ||||
| } | ||||
							
								
								
									
										9
									
								
								src/Event/Query/Truncate.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/Event/Query/Truncate.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,9 @@ | ||||
| <?php | ||||
| 
 | ||||
| namespace Ulmus\Event\Query; | ||||
| 
 | ||||
| use Ulmus\Repository\RepositoryInterface; | ||||
| 
 | ||||
| interface Truncate { | ||||
|     public function execute(RepositoryInterface $repository, ? string $table = null, ? string $alias = null, ? string $schema = null) : void; | ||||
| } | ||||
							
								
								
									
										9
									
								
								src/Event/Query/Update.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/Event/Query/Update.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,9 @@ | ||||
| <?php | ||||
| 
 | ||||
| namespace Ulmus\Event\Query; | ||||
| 
 | ||||
| use Ulmus\Repository\RepositoryInterface; | ||||
| 
 | ||||
| interface Update { | ||||
|     public function execute(RepositoryInterface $repository, object|array $entity, ? array $dataset = null, bool $replace = false) : void; | ||||
| } | ||||
							
								
								
									
										10
									
								
								src/Event/Repository/CollectionFromQueryDatasetInterface.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								src/Event/Repository/CollectionFromQueryDatasetInterface.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,10 @@ | ||||
| <?php | ||||
| 
 | ||||
| namespace Ulmus\Event\Repository; | ||||
| 
 | ||||
| use Ulmus\EntityCollection; | ||||
| use Ulmus\Repository\RepositoryInterface; | ||||
| 
 | ||||
| interface CollectionFromQueryDatasetInterface { | ||||
|     public function execute(RepositoryInterface $repository, array &$data) : void; | ||||
| } | ||||
| @ -2,8 +2,8 @@ | ||||
| 
 | ||||
| namespace Ulmus\Event\Repository; | ||||
| 
 | ||||
| use Ulmus\EntityCollection; | ||||
| use Ulmus\{ EntityCollection, Repository\RepositoryInterface }; | ||||
| 
 | ||||
| interface CollectionFromQueryInterface { | ||||
|     public function execute(EntityCollection $collection) : EntityCollection;     | ||||
|     public function execute(RepositoryInterface $repository, EntityCollection $collection) : EntityCollection; | ||||
| } | ||||
|  | ||||
| @ -15,6 +15,7 @@ class Where extends Fragment { | ||||
|     const CONDITION_OR  = "OR"; | ||||
|     const CONDITION_NOT = "NOT"; | ||||
|     const COMPARISON_IN = "IN"; | ||||
|     const COMPARISON_NOT_IN = "NOT IN"; | ||||
|     const COMPARISON_IS = "IS"; | ||||
|     const COMPARISON_NULL = "NULL"; | ||||
|      | ||||
| @ -100,11 +101,13 @@ class Where extends Fragment { | ||||
|             { | ||||
|                 $value = $this->value(); | ||||
| 
 | ||||
|                 $operator = $this->operator(); | ||||
| 
 | ||||
|                 return $this->content ?: $this->content = implode(" ", array_filter([ | ||||
|                     $this->condition, | ||||
|                     $this->not ? Where::CONDITION_NOT : "", | ||||
|                     $this->field, | ||||
|                     $this->operator(), | ||||
|                     $operator, | ||||
|                     $value, | ||||
|                 ])); | ||||
|             } | ||||
| @ -112,7 +115,11 @@ class Where extends Fragment { | ||||
|             protected function operator() : string | ||||
|             { | ||||
|                 if ( is_array($this->value) ) { | ||||
|                     return Where::COMPARISON_IN; | ||||
|                     if (true === $not = $this->not) { | ||||
|                         $this->not = false; | ||||
|                     } | ||||
| 
 | ||||
|                     return $not ? Where::COMPARISON_NOT_IN : Where::COMPARISON_IN; | ||||
|                 } | ||||
| 
 | ||||
|                 # whitelisting operators
 | ||||
|  | ||||
| @ -4,5 +4,5 @@ namespace Ulmus; | ||||
| 
 | ||||
| class QueryBuilder extends QueryBuilder\Sql\MysqlQueryBuilder | ||||
| { | ||||
|     # Backward compatibility defaulting on MySQL/MariaDB query builder
 | ||||
| 
 | ||||
| } | ||||
| @ -12,4 +12,5 @@ interface QueryBuilderInterface | ||||
|     public function reset() : void; | ||||
|     public function getFragment(string $class, int $index = 0) : ? QueryFragmentInterface; | ||||
|     public function removeFragment(QueryFragmentInterface|array|\Stringable|string $fragment) : void; | ||||
|     public function hashSerializedQuery() : string; | ||||
| } | ||||
| @ -432,8 +432,12 @@ class MysqlQueryBuilder extends SqlQueryBuilder | ||||
|         return array_shift($this->queryStack); | ||||
|     } | ||||
| 
 | ||||
|     public function render(bool $skipToken = false) /* : mixed */ | ||||
|     public function render(bool $skipToken = false) : mixed | ||||
|     { | ||||
|         if (isset($this->rendered)) { | ||||
|             return $this->rendered; | ||||
|         } | ||||
| 
 | ||||
|         $sql = []; | ||||
| 
 | ||||
|         usort($this->queryStack, function($q1, $q2) { | ||||
| @ -444,7 +448,7 @@ class MysqlQueryBuilder extends SqlQueryBuilder | ||||
|             $sql[] = $fragment->render($skipToken); | ||||
|         } | ||||
| 
 | ||||
|         return implode(" ", $sql); | ||||
|         return $this->rendered =  implode(" ", $sql); | ||||
|     } | ||||
| 
 | ||||
|     public function reset() : void | ||||
| @ -453,8 +457,7 @@ class MysqlQueryBuilder extends SqlQueryBuilder | ||||
|         $this->whereConditionOperator = Query\Where::CONDITION_AND; | ||||
|         $this->havingConditionOperator = Query\Where::CONDITION_AND; | ||||
|         $this->parameterIndex = 0; | ||||
| 
 | ||||
|         unset($this->where, $this->having); | ||||
|         unset($this->where, $this->having, $this->rendered, $this->hash); | ||||
|     } | ||||
| 
 | ||||
|     public function getFragment(string $class, int $index = 0) : ? QueryFragmentInterface | ||||
|  | ||||
| @ -7,6 +7,9 @@ use Ulmus\Query\QueryFragmentInterface; | ||||
| # TODO -> Extract from MysqlQueryBuilder to build an ISO/IEC 9075:2023 compatible layer for a basic SQL QueryBuilder
 | ||||
| class SqlQueryBuilder implements QueryBuilderInterface | ||||
| { | ||||
|     protected string $rendered; | ||||
| 
 | ||||
|     protected string $hash; | ||||
| 
 | ||||
|     public function push(QueryFragmentInterface $queryFragment): QueryBuilderInterface | ||||
|     { | ||||
| @ -18,7 +21,7 @@ class SqlQueryBuilder implements QueryBuilderInterface | ||||
|         // TODO: Implement pull() method.
 | ||||
|     } | ||||
| 
 | ||||
|     public function render(bool $skipToken = false) | ||||
|     public function render(bool $skipToken = false) : mixed | ||||
|     { | ||||
|         // TODO: Implement render() method.
 | ||||
|     } | ||||
| @ -37,4 +40,9 @@ class SqlQueryBuilder implements QueryBuilderInterface | ||||
|     { | ||||
|         // TODO: Implement removeFragment() method.
 | ||||
|     } | ||||
| 
 | ||||
|     public function hashSerializedQuery(): string | ||||
|     { | ||||
|         return $this->hash ??= md5(sprintf("%s:%s", $this->render(), serialize($this->parameters))); | ||||
|     } | ||||
| } | ||||
| @ -5,25 +5,27 @@ namespace Ulmus; | ||||
| use Ulmus\Attribute\Property\{ | ||||
|     Field, OrderBy, Where, Having, Relation, Filter, Join, FilterJoin, WithJoin | ||||
| }; | ||||
| use Psr\SimpleCache\CacheInterface; | ||||
| use Ulmus\Common\EntityResolver; | ||||
| use Ulmus\Entity\EntityInterface; | ||||
| use Ulmus\Repository\RepositoryInterface; | ||||
| use Ulmus\Repository\WithOptionEnum; | ||||
| 
 | ||||
| class Repository implements RepositoryInterface | ||||
| { | ||||
|     use EventTrait, Repository\ConditionTrait, Repository\EscapeTrait; | ||||
|     use EventTrait, CacheTrait, Repository\ConditionTrait, Repository\EscapeTrait, Repository\QueryBuildingTrait; | ||||
| 
 | ||||
|     const DEFAULT_ALIAS = "this"; | ||||
| 
 | ||||
|     public ? ConnectionAdapter $adapter; | ||||
| 
 | ||||
|     public string $alias; | ||||
| 
 | ||||
|     public string $entityClass; | ||||
| 
 | ||||
|     public array $events = []; | ||||
| 
 | ||||
|     protected QueryBuilder\QueryBuilderInterface $queryBuilder; | ||||
|     public ? ConnectionAdapter $adapters; | ||||
| 
 | ||||
|     public readonly QueryBuilder\QueryBuilderInterface $queryBuilder; | ||||
| 
 | ||||
|     protected EntityResolver $entityResolver; | ||||
| 
 | ||||
| @ -33,10 +35,21 @@ class Repository implements RepositoryInterface | ||||
|         $this->entityClass = $entity; | ||||
|         $this->alias = $alias; | ||||
|         $this->entityResolver = Ulmus::resolveEntity($entity); | ||||
|         $this->adapter = $adapter ?? $this->entityResolver->databaseAdapter(); | ||||
| 
 | ||||
|         $queryBuilder = $this->adapter->adapter()->queryBuilderClass(); | ||||
|         $this->queryBuilder = new $queryBuilder(); | ||||
|         if ($adapter) { | ||||
|             $this->adapter = $adapter; | ||||
| 
 | ||||
|             $qbClass = $adapter->adapter()->queryBuilderClass(); | ||||
|             $this->queryBuilder = new $qbClass(); | ||||
|         } | ||||
|         else { | ||||
|             $this->adapter = $this->entityResolver->databaseAdapter(); | ||||
|             $this->queryBuilder = $this->entityClass::queryBuilder(); | ||||
|         } | ||||
| 
 | ||||
|         if ($this->adapter->cacheObject) { | ||||
|             $this->attachCachingObject($this->adapter->cacheObject); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public function __clone() | ||||
| @ -113,6 +126,8 @@ class Repository implements RepositoryInterface | ||||
| 
 | ||||
|     public function deleteAll() | ||||
|     { | ||||
|         $this->eventExecute(Event\Query\Delete::class, $this); | ||||
| 
 | ||||
|         return $this->deleteSqlQuery()->runDeleteQuery(); | ||||
|     } | ||||
| 
 | ||||
| @ -139,6 +154,8 @@ class Repository implements RepositoryInterface | ||||
|         else { | ||||
|             $pkField = key($primaryKeyDefinition); | ||||
| 
 | ||||
|             $this->eventExecute(Event\Query\Delete::class, $this, $entity); | ||||
| 
 | ||||
|             return $this->deleteFromPk($entity->$pkField); | ||||
|         } | ||||
|     } | ||||
| @ -193,6 +210,8 @@ class Repository implements RepositoryInterface | ||||
| 
 | ||||
|             $entity->entityFillFromDataset($dataset, true); | ||||
| 
 | ||||
|             $this->eventExecute(Event\Query\Insert::class, $this, $entity, $dataset, $replace); | ||||
| 
 | ||||
|             return (bool) ( $pkValue ?? $pdoObject->lastInsertId ); | ||||
|         } | ||||
|         else { | ||||
| @ -211,6 +230,9 @@ class Repository implements RepositoryInterface | ||||
| 
 | ||||
|                 $entity->entityFillFromDataset($dataset, true); | ||||
| 
 | ||||
|                 # $fieldsAndValue ??= &$dataset;
 | ||||
|                 $this->eventExecute(Event\Query\Update::class, $this, $entity, $dataset, $replace); | ||||
| 
 | ||||
|                 return $update ? (bool) $update->rowCount : false; | ||||
|             } | ||||
|         } | ||||
| @ -229,64 +251,6 @@ class Repository implements RepositoryInterface | ||||
|         return $changed; | ||||
|     } | ||||
| 
 | ||||
|     public function insertAll(EntityCollection|array $collection, int $size = 1000) : int | ||||
|     { | ||||
|         if ( empty($collection) ) { | ||||
|             return 0; | ||||
|         } | ||||
|         elseif ( is_array($collection) ) { | ||||
|             $collection = $this->entityClass::entityCollection($collection); | ||||
|         } | ||||
| 
 | ||||
|         foreach($collection as $entity) { | ||||
|             if  ( ! $this->matchEntity($entity) ) { | ||||
|                 throw new \Exception("Your entity class `" . get_class($entity) . "` cannot match entity type of repository `{$this->entityClass}`"); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         $dataset = $entity->toArray(); | ||||
| 
 | ||||
|         $primaryKeyDefinition = Ulmus::resolveEntity($this->entityClass)->getPrimaryKeyField(); | ||||
| 
 | ||||
|         if ( ! $entity->isLoaded() ) { | ||||
|             # $dataset = array_filter($dataset, fn($item, $field) => ! ($this->entityResolver->searchFieldAnnotation($field, new Field, false)->readonly ?? false), \ARRAY_FILTER_USE_BOTH);
 | ||||
| 
 | ||||
|             $statement = $this->insertSqlQuery($fieldsAndValue ?? $dataset, $replace)->runInsertQuery(); | ||||
| 
 | ||||
|             if ( ( 0 !== $statement->lastInsertId ) && | ||||
|                 ( null !== $primaryKeyDefinition )) { | ||||
| 
 | ||||
|                 $pkField = key($primaryKeyDefinition); | ||||
|                 $dataset[$pkField] = $statement->lastInsertId; | ||||
|             } | ||||
| 
 | ||||
|             $entity->entityFillFromDataset($dataset, true); | ||||
| 
 | ||||
|             return (bool) $statement->lastInsertId; | ||||
|         } | ||||
|         else { | ||||
|             if ( $primaryKeyDefinition === null ) { | ||||
|                 throw new \Exception(sprintf("No primary key found for entity %s", $this->entityClass)); | ||||
|             } | ||||
| 
 | ||||
|             $diff = $fieldsAndValue ?? $this->generateWritableDataset($entity); | ||||
| 
 | ||||
|             if ( [] !== $diff ) { | ||||
|                 $pkField = key($primaryKeyDefinition); | ||||
|                 $pkFieldName = $primaryKeyDefinition[$pkField]->name ?? $pkField; | ||||
|                 $this->where($pkFieldName, $dataset[$pkFieldName]); | ||||
| 
 | ||||
|                 $update = $this->updateSqlQuery($diff)->runUpdateQuery(); | ||||
| 
 | ||||
|                 $entity->entityFillFromDataset($dataset, true); | ||||
| 
 | ||||
|                 return $update ? (bool) $update->rowCount : false; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         return 0; | ||||
|     } | ||||
| 
 | ||||
|     public function replace(object|array $entity, ? array $fieldsAndValue = null) : bool | ||||
|     { | ||||
|         return $this->save($entity, $fieldsAndValue, true); | ||||
| @ -303,35 +267,34 @@ class Repository implements RepositoryInterface | ||||
|         return $changed; | ||||
|     } | ||||
| 
 | ||||
|     public function truncate(? string $table = null, ? string $alias = null, ? string $schema = null) : self | ||||
| 
 | ||||
|     public function createTable() : mixed | ||||
|     { | ||||
|         $schema = $schema ?: $this->entityResolver->schemaName(); | ||||
|         $this->eventExecute(Event\Query\Create::class, $this); | ||||
| 
 | ||||
|         $this->queryBuilder->truncate($this->escapeTable($table ?: $this->entityResolver->tableName()), $this->escapeIdentifier($alias ?: $this->alias), $this->escapedDatabase(), $schema ? $this->escapeSchema($schema) : null); | ||||
| 
 | ||||
|         $this->finalizeQuery(); | ||||
| 
 | ||||
|         # ??? $result = Ulmus::runSelectQuery($this->queryBuilder, $this->adapter);
 | ||||
| 
 | ||||
|         return $this; | ||||
|     } | ||||
| 
 | ||||
|     public function createTable() | ||||
|     { | ||||
|         return $this->createSqlQuery()->runQuery(); | ||||
|     } | ||||
| 
 | ||||
|     public function alterTable(array $fields) | ||||
|     public function alterTable(array $fields) : mixed | ||||
|     { | ||||
|         $this->eventExecute(Event\Query\Alter::class, $this, $fields); | ||||
| 
 | ||||
|         return $this->alterSqlQuery($fields)->runQuery(); | ||||
|     } | ||||
| 
 | ||||
|     public function listTables(? string $database = null) | ||||
|     public function truncateTable() : mixed | ||||
|     { | ||||
|         $this->eventExecute(Event\Query\Truncate::class, $this, $table, $alias, $schema); | ||||
| 
 | ||||
|         return $this->truncate()->runQuery(); | ||||
|     } | ||||
| 
 | ||||
|     public function listTables(? string $database = null) : mixed | ||||
|     { | ||||
|         return $this->showTablesSqlQuery($database)->runQuery(); | ||||
|     } | ||||
| 
 | ||||
|     public function listColumns(? string $table = null) | ||||
|     public function listColumns(? string $table = null) : EntityCollection | ||||
|     { | ||||
|         $table ??= $this->entityResolver->tableName(); | ||||
| 
 | ||||
| @ -358,11 +321,8 @@ class Repository implements RepositoryInterface | ||||
| 
 | ||||
|             return (string) $e1 !== (string) $e2; | ||||
|         }); | ||||
| 
 | ||||
|         # return array_diff_assoc($oldValues ? $dataset : $array , $oldValues ? $array : $dataset );
 | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     public function generateWritableDataset(object $entity, bool $oldValues = false) : array | ||||
|     { | ||||
|         $intersect = []; | ||||
| @ -370,7 +330,7 @@ class Repository implements RepositoryInterface | ||||
|         $dataset = $this->generateDatasetDiff($entity, $oldValues); | ||||
| 
 | ||||
|         foreach($dataset as $field => $value) { | ||||
|             if ( false === ( $this->entityResolver->searchFieldAnnotation($field, [ Field::class, Field::class ], false)->readonly ?? false ) ) { | ||||
|             if ( false === ( $this->entityResolver->searchFieldAnnotation($field, Field::class, false)->readonly ?? false ) ) { | ||||
|                 $intersect[$field] = $field; | ||||
|             } | ||||
|         } | ||||
| @ -389,15 +349,6 @@ class Repository implements RepositoryInterface | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public function removeQueryFragment(null|Query\QueryFragmentInterface|string|array $fragment) : self | ||||
|     { | ||||
|         foreach((array) $fragment as $item) { | ||||
|             $this->queryBuilder->removeFragment($item); | ||||
|         } | ||||
| 
 | ||||
|         return $this; | ||||
|     } | ||||
| 
 | ||||
|     public function selectEntity(string $entity, string $alias, string $prependField = "") : self | ||||
|     { | ||||
|         $prependField and ($prependField .= "$"); | ||||
| @ -431,167 +382,6 @@ class Repository implements RepositoryInterface | ||||
|         ); | ||||
|     } | ||||
| 
 | ||||
|     public function select(array|string|\Stringable $fields, bool $distinct = false) : self | ||||
|     { | ||||
|         $this->queryBuilder->select($fields, $distinct); | ||||
| 
 | ||||
|         return $this; | ||||
|     } | ||||
| 
 | ||||
|     public function distinct(array|string|\Stringable $fields) : self | ||||
|     { | ||||
|         $this->queryBuilder->select($fields); | ||||
|         $this->queryBuilder->getFragment(Query\Select::class)->distinct = true; | ||||
| 
 | ||||
|         return $this; | ||||
|     } | ||||
| 
 | ||||
|     public function insert(array $fieldlist, string $table, string $alias, ? string $schema, bool $replace = false) : self | ||||
|     { | ||||
|         $this->queryBuilder->insert($fieldlist, $this->escapeTable($table), $this->escapeIdentifier($alias), $this->escapedDatabase(), $schema, $replace); | ||||
| 
 | ||||
|         return $this; | ||||
|     } | ||||
| 
 | ||||
|     public function values(array $dataset) : self | ||||
|     { | ||||
|         $this->queryBuilder->values($dataset); | ||||
|         return $this; | ||||
|     } | ||||
| 
 | ||||
|     public function update(string $table, string $alias, ? string $schema) : self | ||||
|     { | ||||
|         $this->queryBuilder->update($this->escapeTable($table), $alias ? $this->escapeIdentifier($alias) : null, $this->escapedDatabase(), $schema); | ||||
| 
 | ||||
|         return $this; | ||||
|     } | ||||
| 
 | ||||
|     public function set(array $dataset) : self | ||||
|     { | ||||
|         $keys = array_keys($dataset); | ||||
|         $escapedFields = array_combine($keys, array_map([ $this, 'escapeField' ], $keys)); | ||||
| 
 | ||||
|         $this->queryBuilder->set($dataset, $escapedFields); | ||||
| 
 | ||||
|         return $this; | ||||
|     } | ||||
| 
 | ||||
|     public function delete(...$args) : self | ||||
|     { | ||||
|         $this->queryBuilder->delete(); | ||||
| 
 | ||||
|         return $this; | ||||
|     } | ||||
| 
 | ||||
|     public function from(string $table, ? string $alias, ? string $schema) : self | ||||
|     { | ||||
|         $this->queryBuilder->from($this->escapeTable($table), $alias ? $this->escapeIdentifier($alias) : null, $this->escapedDatabase(), $schema ? $this->escapeSchema($schema) : null); | ||||
|          | ||||
|         return $this; | ||||
|     } | ||||
| 
 | ||||
|     public function join(string $type, $table, string|\Stringable $field, mixed $value, ? string $alias = null, ? callable $callback = null) : self | ||||
|     { | ||||
|         $join = $this->queryBuilder->withJoin($type, $this->escapeTable($table), $field, $value, false, $alias ? $this->escapeIdentifier($alias) : null); | ||||
| 
 | ||||
|         if ( $callback ) { | ||||
|             $callback($join); | ||||
|         } | ||||
| 
 | ||||
|         return $this; | ||||
|     } | ||||
| 
 | ||||
|     public function outerJoin(string $type, $table, string|\Stringable $field, mixed $value, ? string $alias = null, ? callable $callback = null) : self | ||||
|     { | ||||
|         $join = $this->queryBuilder->withJoin($type, $this->escapeTable($table), $field, $value, true, $alias ? $this->escapeIdentifier($alias) : null); | ||||
| 
 | ||||
|         if ( $callback ) { | ||||
|             $callback($join); | ||||
|         } | ||||
| 
 | ||||
|         return $this; | ||||
|     } | ||||
| 
 | ||||
|     public function match() : self | ||||
|     { | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     public function notMatch() : self | ||||
|     { | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     public function between() : self | ||||
|     { | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     public function notBetween() : self | ||||
|     { | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     public function groupBy(string|\Stringable $field) : self | ||||
|     { | ||||
|         $this->queryBuilder->groupBy($field); | ||||
| 
 | ||||
|         return $this; | ||||
|     } | ||||
| 
 | ||||
|     public function groups(array $groups) : self | ||||
|     { | ||||
|         foreach($groups as $field ) { | ||||
|             $this->groupBy($field); | ||||
|         } | ||||
| 
 | ||||
|         return $this; | ||||
|     } | ||||
| 
 | ||||
|     public function orderBy(string|\Stringable $field, null|string|\Stringable $direction = null) : self | ||||
|     { | ||||
|         $this->queryBuilder->orderBy($field, $direction); | ||||
| 
 | ||||
|         return $this; | ||||
|     } | ||||
| 
 | ||||
|     # @UNTESTED
 | ||||
|     public function randomizeOrder() : self | ||||
|     { | ||||
|         $this->queryBuilder->orderBy(Common\Sql::function('RAND', Common\Sql::identifier('CURDATE()+0'))); | ||||
| 
 | ||||
|         return $this; | ||||
|     } | ||||
| 
 | ||||
|     public function orders(array $orderList) : self | ||||
|     { | ||||
|         foreach($orderList as $field => $direction) { | ||||
|             if (is_numeric($field)) { | ||||
|                 $this->orderBy($direction); | ||||
|             } | ||||
|             else { | ||||
|                 # Associative array with direction
 | ||||
|                 $this->orderBy($field, $direction); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         return $this; | ||||
|     } | ||||
| 
 | ||||
|     public function limit(int $value) : self | ||||
|     { | ||||
|         $this->queryBuilder->limit($value); | ||||
| 
 | ||||
|         return $this; | ||||
|     } | ||||
| 
 | ||||
|     public function offset(int $value) : self | ||||
|     { | ||||
|         $this->queryBuilder->offset($value); | ||||
| 
 | ||||
|         return $this; | ||||
|     } | ||||
| 
 | ||||
|     /* @TODO */ | ||||
|     public function commit() : self | ||||
|     { | ||||
| @ -686,23 +476,23 @@ class Repository implements RepositoryInterface | ||||
|                 $foreignKey = is_string($attribute->foreignKey) ? $entity::field($attribute->foreignKey, $alias) : $attribute->foreignKey; | ||||
| 
 | ||||
|                 $this->join("LEFT", $entity::resolveEntity()->tableName(), $key, $foreignKey, $alias, function($join) use ($item, $entity, $alias, $options) { | ||||
|                     if (  !  in_array(WithOptionEnum::SkipJoinWhere, $options)) { | ||||
|                     foreach($this->entityResolver->searchFieldAnnotationList($item, [ Where::class ]) as $condition) { | ||||
|                         if ( ! is_object($condition->field) ) { | ||||
|                             $field = $this->entityClass::field($condition->field); | ||||
|                         } | ||||
|                         else { | ||||
|                             $field = clone $condition->field; | ||||
|                         } | ||||
|                     if ( ! in_array(WithOptionEnum::SkipJoinWhere, $options)) { | ||||
|                         foreach($this->entityResolver->searchFieldAnnotationList($item, [ Where::class ]) as $condition) { | ||||
|                             if ( ! is_object($condition->field) ) { | ||||
|                                 $field = $this->entityClass::field($condition->field); | ||||
|                             } | ||||
|                             else { | ||||
|                                 $field = clone $condition->field; | ||||
|                             } | ||||
| 
 | ||||
|                         # Adding directly
 | ||||
|                         if ( $field->entityClass === $entity ) { | ||||
|                             $field->alias = $alias; | ||||
|                             # Adding directly
 | ||||
|                             if ( $field->entityClass === $entity ) { | ||||
|                                 $field->alias = $alias; | ||||
| 
 | ||||
|                             $join->where(is_object($field) ? $field : $entity::field($field, $alias), $condition->getValue(), $condition->operator); | ||||
|                                 $join->where(is_object($field) ? $field : $entity::field($field, $alias), $condition->getValue(), $condition->operator); | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|                     } | ||||
| 
 | ||||
|                     if ( ! in_array(WithOptionEnum::SkipJoinFilter, $options) ) { | ||||
|                          foreach ($this->entityResolver->searchFieldAnnotationList($item, [ FilterJoin::class ]) as $filter) { | ||||
| @ -804,7 +594,7 @@ class Repository implements RepositoryInterface | ||||
| 
 | ||||
|                 foreach ($where as $condition) { | ||||
|                     # $repository->where($condition->field, is_callable($condition->value) ? call_user_func_array($condition->value, [$this]) : $condition->getValue(), $condition->operator, $condition->condition);
 | ||||
|                     $repository->where($condition->field, $condition->getValue($this), $condition->operator, $condition->condition); | ||||
|                     $repository->where($condition->field, $condition->getValue(/* why repository sent here ??? $this */), $condition->operator, $condition->condition); | ||||
|                 } | ||||
| 
 | ||||
|                 foreach ($order as $item) { | ||||
| @ -873,17 +663,21 @@ class Repository implements RepositoryInterface | ||||
|         $entityCollection = $entityClass::entityCollection(); | ||||
| 
 | ||||
|         $this->finalizeQuery(); | ||||
|          | ||||
|         foreach(Ulmus::iterateQueryBuilder($this->queryBuilder, $this->adapter) as $entityData) { | ||||
| 
 | ||||
|         $dataset = []; | ||||
| 
 | ||||
|         $this->eventExecute(\Ulmus\Event\Repository\CollectionFromQueryDatasetInterface::class, $this, $dataset); | ||||
| 
 | ||||
|         foreach($dataset ?: Ulmus::iterateQueryBuilder($this->queryBuilder, $this->adapter) as $entityData) { | ||||
|             $this->eventExecute(\Ulmus\Event\Repository\CollectionFromQueryItemInterface::class, $entityData); | ||||
| 
 | ||||
|             $entity = $this->instanciateEntity($entityClass); | ||||
|             $entity->loadedFromAdapter = $this->adapter->name; | ||||
| 
 | ||||
|             $entityCollection->append( $entity->resetVirtualProperties()->entityFillFromDataset($entityData) ); | ||||
|             $entityCollection->append( $entity->entityFillFromDataset($entityData) ); | ||||
|         } | ||||
| 
 | ||||
|         $this->eventExecute(Event\Repository\CollectionFromQueryInterface::class, $entityCollection); | ||||
|         $this->eventExecute(Event\Repository\CollectionFromQueryInterface::class, $this, $entityCollection); | ||||
| 
 | ||||
|         return $entityCollection; | ||||
|     } | ||||
| @ -925,110 +719,6 @@ class Repository implements RepositoryInterface | ||||
|         return Ulmus::runDeleteQuery($this->queryBuilder, $this->adapter); | ||||
|     } | ||||
| 
 | ||||
|     public function resetQuery() : self | ||||
|     { | ||||
|         $this->queryBuilder->reset(); | ||||
| 
 | ||||
|         return $this; | ||||
|     } | ||||
| 
 | ||||
|     protected function insertSqlQuery(array $dataset, bool $replace = false) : self | ||||
|     { | ||||
|         if ( null === $insert = $this->queryBuilder->getFragment(Query\Insert::class) ) { | ||||
|             $this->insert(array_map([ $this, 'escapeField' ] , array_keys($dataset)), $this->entityResolver->tableName(), $this->alias, $this->entityResolver->schemaName(), $replace); | ||||
|         } | ||||
|         else { | ||||
|             $insert->replace = $replace; | ||||
|         } | ||||
| 
 | ||||
|         $this->values($dataset); | ||||
| 
 | ||||
|         return $this; | ||||
|     } | ||||
| 
 | ||||
|     protected function updateSqlQuery(array $dataset) : self | ||||
|     { | ||||
|         if ( null === $this->queryBuilder->getFragment(Query\Update::class) ) { | ||||
|             $this->update($this->entityResolver->tableName(), $this->alias, $this->entityResolver->schemaName()); | ||||
|         } | ||||
| 
 | ||||
|         $this->set($dataset); | ||||
| 
 | ||||
|         return $this; | ||||
|     } | ||||
| 
 | ||||
|     protected function selectSqlQuery() : self | ||||
|     { | ||||
|         if ( null === $this->queryBuilder->getFragment(Query\Select::class) ) { | ||||
|             $fields = $this->entityResolver->fieldList(EntityResolver::KEY_COLUMN_NAME, true); | ||||
|             $this->select($this->entityClass::fields(array_map(fn($f) => $f->object->name ?? $f->name, $fields))); | ||||
|         } | ||||
| 
 | ||||
|         if ( null === $this->queryBuilder->getFragment(Query\From::class) ) { | ||||
|             $this->from($this->entityResolver->tableName(), $this->alias, $this->entityResolver->schemaName()); | ||||
|         } | ||||
| 
 | ||||
|         return $this; | ||||
|     } | ||||
| 
 | ||||
|     protected function deleteSqlQuery() : self | ||||
|     { | ||||
|         if ( null === $this->queryBuilder->getFragment(Query\Delete::class) ) { | ||||
|             $this->delete(); | ||||
|         } | ||||
| 
 | ||||
|         if ( null === $this->queryBuilder->getFragment(Query\From::class) ) { | ||||
|             $this->from($this->entityResolver->tableName(), null, $this->entityResolver->schemaName()); | ||||
|         } | ||||
| 
 | ||||
|         return $this; | ||||
|     } | ||||
| 
 | ||||
|     public function createSqlQuery() : self | ||||
|     { | ||||
|         if ( null === $this->queryBuilder->getFragment(Query\Create::class) ) { | ||||
|             $this->queryBuilder->create($this->adapter->adapter(), $this->escapeFieldList($this->entityResolver->fieldList(EntityResolver::KEY_ENTITY_NAME, true)), $this->escapeTable($this->entityResolver->tableName()), $this->entityResolver->schemaName()); | ||||
|         } | ||||
| 
 | ||||
|         return $this; | ||||
|     } | ||||
| 
 | ||||
|     public function alterSqlQuery(array $fields) : self | ||||
|     { | ||||
|         if ( null === $this->queryBuilder->getFragment(Query\Alter::class) ) { | ||||
|             $this->queryBuilder->alter($this->adapter->adapter(), $fields, $this->escapeTable($this->entityResolver->tableName()), $this->entityResolver->schemaName()); | ||||
|         } | ||||
| 
 | ||||
|         return $this; | ||||
|     } | ||||
| 
 | ||||
|     public function showDatabasesSqlQuery() : self | ||||
|     { | ||||
|         if ( null === $this->queryBuilder->getFragment(Query\Show::class) ) { | ||||
|             $this->queryBuilder->showDatabases(); | ||||
|         } | ||||
| 
 | ||||
|         return $this; | ||||
|     } | ||||
| 
 | ||||
|     public function showTablesSqlQuery() : self | ||||
|     { | ||||
|         if ( null === $this->queryBuilder->getFragment(Query\Show::class) ) { | ||||
|             $this->queryBuilder->showTables(); | ||||
|         } | ||||
| 
 | ||||
|         return $this; | ||||
|     } | ||||
| 
 | ||||
|     public function showColumnsSqlQuery(string $table) : self | ||||
|     { | ||||
|         if ( null === $this->queryBuilder->getFragment(Query\Show::class) ) { | ||||
|             $this->queryBuilder->showColumns($table); | ||||
|         } | ||||
| 
 | ||||
|         return $this; | ||||
|     } | ||||
| 
 | ||||
|     protected function fromRow($row) : self | ||||
|     { | ||||
| 
 | ||||
| @ -1039,15 +729,6 @@ class Repository implements RepositoryInterface | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     public function getSqlQuery(bool $flush = true) : string | ||||
|     { | ||||
|         $result = $this->queryBuilder->render(); | ||||
| 
 | ||||
|         $flush and $this->queryBuilder->reset(); | ||||
| 
 | ||||
|         return $result; | ||||
|     } | ||||
| 
 | ||||
|     public function instanciateEntityCollection(...$arguments) : EntityCollection | ||||
|     { | ||||
|         return $this->entityClass::entityCollection(...$arguments); | ||||
|  | ||||
| @ -151,7 +151,7 @@ trait ConditionTrait | ||||
|         return $this; | ||||
|     } | ||||
| 
 | ||||
|     public function removeQueryFragment(Query\Fragment|\Stringable|string|array $fragment) : self | ||||
|     public function removeQueryFragment(null|Query\QueryFragmentInterface|string|\Stringable|array $fragment) : self | ||||
|     { | ||||
|         foreach((array) $fragment as $item) { | ||||
|             $this->queryBuilder->removeFragment($item); | ||||
|  | ||||
							
								
								
									
										292
									
								
								src/Repository/QueryBuildingTrait.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										292
									
								
								src/Repository/QueryBuildingTrait.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,292 @@ | ||||
| <?php | ||||
| 
 | ||||
| namespace Ulmus\Repository; | ||||
| 
 | ||||
| use Ulmus\{Common\EntityResolver, Query, Common}; | ||||
| 
 | ||||
| trait QueryBuildingTrait | ||||
| { | ||||
|     public function truncate(? string $table = null, ? string $alias = null, ? string $schema = null) : self | ||||
|     { | ||||
|         $schema = $schema ?: $this->entityResolver->schemaName(); | ||||
| 
 | ||||
|         $this->queryBuilder->truncate($this->escapeTable($table ?: $this->entityResolver->tableName()), $this->escapeIdentifier($alias ?: $this->alias), $this->escapedDatabase(), $schema ? $this->escapeSchema($schema) : null); | ||||
| 
 | ||||
|         return $this; | ||||
|     } | ||||
| 
 | ||||
|     public function select(array|string|\Stringable $fields, bool $distinct = false) : self | ||||
|     { | ||||
|         $this->queryBuilder->select($fields, $distinct); | ||||
| 
 | ||||
|         return $this; | ||||
|     } | ||||
| 
 | ||||
|     public function distinct(array|string|\Stringable $fields) : self | ||||
|     { | ||||
|         $this->queryBuilder->select($fields); | ||||
|         $this->queryBuilder->getFragment(Query\Select::class)->distinct = true; | ||||
| 
 | ||||
|         return $this; | ||||
|     } | ||||
| 
 | ||||
|     public function insert(array $fieldlist, string $table, string $alias, ? string $schema, bool $replace = false) : self | ||||
|     { | ||||
|         $this->queryBuilder->insert($fieldlist, $this->escapeTable($table), $this->escapeIdentifier($alias), $this->escapedDatabase(), $schema, $replace); | ||||
| 
 | ||||
|         return $this; | ||||
|     } | ||||
| 
 | ||||
|     public function values(array $dataset) : self | ||||
|     { | ||||
|         $this->queryBuilder->values($dataset); | ||||
|         return $this; | ||||
|     } | ||||
| 
 | ||||
|     public function update(string $table, string $alias, ? string $schema) : self | ||||
|     { | ||||
|         $this->queryBuilder->update($this->escapeTable($table), $alias ? $this->escapeIdentifier($alias) : null, $this->escapedDatabase(), $schema); | ||||
| 
 | ||||
|         return $this; | ||||
|     } | ||||
| 
 | ||||
|     public function set(array $dataset) : self | ||||
|     { | ||||
|         $keys = array_keys($dataset); | ||||
|         $escapedFields = array_combine($keys, array_map([ $this, 'escapeField' ], $keys)); | ||||
| 
 | ||||
|         $this->queryBuilder->set($dataset, $escapedFields); | ||||
| 
 | ||||
|         return $this; | ||||
|     } | ||||
| 
 | ||||
|     public function delete(...$args) : self | ||||
|     { | ||||
|         $this->queryBuilder->delete(); | ||||
| 
 | ||||
|         return $this; | ||||
|     } | ||||
| 
 | ||||
|     public function from(string $table, ? string $alias, ? string $schema) : self | ||||
|     { | ||||
|         $this->queryBuilder->from($this->escapeTable($table), $alias ? $this->escapeIdentifier($alias) : null, $this->escapedDatabase(), $schema ? $this->escapeSchema($schema) : null); | ||||
| 
 | ||||
|         return $this; | ||||
|     } | ||||
| 
 | ||||
|     public function join(string $type, $table, string|\Stringable $field, mixed $value, ? string $alias = null, ? callable $callback = null) : self | ||||
|     { | ||||
|         $join = $this->queryBuilder->withJoin($type, $this->escapeTable($table), $field, $value, false, $alias ? $this->escapeIdentifier($alias) : null); | ||||
| 
 | ||||
|         if ( $callback ) { | ||||
|             $callback($join); | ||||
|         } | ||||
| 
 | ||||
|         return $this; | ||||
|     } | ||||
| 
 | ||||
|     public function outerJoin(string $type, $table, string|\Stringable $field, mixed $value, ? string $alias = null, ? callable $callback = null) : self | ||||
|     { | ||||
|         $join = $this->queryBuilder->withJoin($type, $this->escapeTable($table), $field, $value, true, $alias ? $this->escapeIdentifier($alias) : null); | ||||
| 
 | ||||
|         if ( $callback ) { | ||||
|             $callback($join); | ||||
|         } | ||||
| 
 | ||||
|         return $this; | ||||
|     } | ||||
| 
 | ||||
|     public function match() : self | ||||
|     { | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     public function notMatch() : self | ||||
|     { | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     public function between() : self | ||||
|     { | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     public function notBetween() : self | ||||
|     { | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     public function groupBy(string|\Stringable $field) : self | ||||
|     { | ||||
|         $this->queryBuilder->groupBy($field); | ||||
| 
 | ||||
|         return $this; | ||||
|     } | ||||
| 
 | ||||
|     public function groups(array $groups) : self | ||||
|     { | ||||
|         foreach($groups as $field ) { | ||||
|             $this->groupBy($field); | ||||
|         } | ||||
| 
 | ||||
|         return $this; | ||||
|     } | ||||
| 
 | ||||
|     public function orderBy(string|\Stringable $field, null|string|\Stringable $direction = null) : self | ||||
|     { | ||||
|         $this->queryBuilder->orderBy($field, $direction); | ||||
| 
 | ||||
|         return $this; | ||||
|     } | ||||
| 
 | ||||
|     # @UNTESTED
 | ||||
|     public function randomizeOrder() : self | ||||
|     { | ||||
|         $this->queryBuilder->orderBy(Common\Sql::function('RAND', Common\Sql::identifier('CURDATE()+0'))); | ||||
| 
 | ||||
|         return $this; | ||||
|     } | ||||
| 
 | ||||
|     public function orders(array $orderList) : self | ||||
|     { | ||||
|         foreach($orderList as $field => $direction) { | ||||
|             if (is_numeric($field)) { | ||||
|                 $this->orderBy($direction); | ||||
|             } | ||||
|             else { | ||||
|                 # Associative array with direction
 | ||||
|                 $this->orderBy($field, $direction); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         return $this; | ||||
|     } | ||||
| 
 | ||||
|     public function limit(int $value) : self | ||||
|     { | ||||
|         $this->queryBuilder->limit($value); | ||||
| 
 | ||||
|         return $this; | ||||
|     } | ||||
| 
 | ||||
|     public function offset(int $value) : self | ||||
|     { | ||||
|         $this->queryBuilder->offset($value); | ||||
| 
 | ||||
|         return $this; | ||||
|     } | ||||
| 
 | ||||
|     public function getSqlQuery(bool $flush = true) : string | ||||
|     { | ||||
|         $result = $this->queryBuilder->render(); | ||||
| 
 | ||||
|         $flush and $this->queryBuilder->reset(); | ||||
| 
 | ||||
|         return $result; | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     public function resetQuery() : self | ||||
|     { | ||||
|         $this->queryBuilder->reset(); | ||||
| 
 | ||||
|         return $this; | ||||
|     } | ||||
| 
 | ||||
|     protected function insertSqlQuery(array $dataset, bool $replace = false) : self | ||||
|     { | ||||
|         if ( null === $insert = $this->queryBuilder->getFragment(Query\Insert::class) ) { | ||||
|             $this->insert(array_map([ $this, 'escapeField' ] , array_keys($dataset)), $this->entityResolver->tableName(), $this->alias, $this->entityResolver->schemaName(), $replace); | ||||
|         } | ||||
|         else { | ||||
|             $insert->replace = $replace; | ||||
|         } | ||||
| 
 | ||||
|         $this->values($dataset); | ||||
| 
 | ||||
|         return $this; | ||||
|     } | ||||
| 
 | ||||
|     protected function updateSqlQuery(array $dataset) : self | ||||
|     { | ||||
|         if ( null === $this->queryBuilder->getFragment(Query\Update::class) ) { | ||||
|             $this->update($this->entityResolver->tableName(), $this->alias, $this->entityResolver->schemaName()); | ||||
|         } | ||||
| 
 | ||||
|         $this->set($dataset); | ||||
| 
 | ||||
|         return $this; | ||||
|     } | ||||
| 
 | ||||
|     protected function selectSqlQuery() : self | ||||
|     { | ||||
|         if ( null === $this->queryBuilder->getFragment(Query\Select::class) ) { | ||||
|             $fields = $this->entityResolver->fieldList(EntityResolver::KEY_COLUMN_NAME, true); | ||||
|             $this->select($this->entityClass::fields(array_map(fn($f) => $f->object->name ?? $f->name, $fields))); | ||||
|         } | ||||
| 
 | ||||
|         if ( null === $this->queryBuilder->getFragment(Query\From::class) ) { | ||||
|             $this->from($this->entityResolver->tableName(), $this->alias, $this->entityResolver->schemaName()); | ||||
|         } | ||||
| 
 | ||||
|         return $this; | ||||
|     } | ||||
| 
 | ||||
|     protected function deleteSqlQuery() : self | ||||
|     { | ||||
|         if ( null === $this->queryBuilder->getFragment(Query\Delete::class) ) { | ||||
|             $this->delete(); | ||||
|         } | ||||
| 
 | ||||
|         if ( null === $this->queryBuilder->getFragment(Query\From::class) ) { | ||||
|             $this->from($this->entityResolver->tableName(), null, $this->entityResolver->schemaName()); | ||||
|         } | ||||
| 
 | ||||
|         return $this; | ||||
|     } | ||||
| 
 | ||||
|     public function createSqlQuery() : self | ||||
|     { | ||||
|         if ( null === $this->queryBuilder->getFragment(Query\Create::class) ) { | ||||
|             $this->queryBuilder->create($this->adapter->adapter(), $this->escapeFieldList($this->entityResolver->fieldList(EntityResolver::KEY_ENTITY_NAME, true)), $this->escapeTable($this->entityResolver->tableName()), $this->entityResolver->schemaName()); | ||||
|         } | ||||
| 
 | ||||
|         return $this; | ||||
|     } | ||||
| 
 | ||||
|     public function alterSqlQuery(array $fields) : self | ||||
|     { | ||||
|         if ( null === $this->queryBuilder->getFragment(Query\Alter::class) ) { | ||||
|             $this->queryBuilder->alter($this->adapter->adapter(), $fields, $this->escapeTable($this->entityResolver->tableName()), $this->entityResolver->schemaName()); | ||||
|         } | ||||
| 
 | ||||
|         return $this; | ||||
|     } | ||||
| 
 | ||||
|     public function showDatabasesSqlQuery() : self | ||||
|     { | ||||
|         if ( null === $this->queryBuilder->getFragment(Query\Show::class) ) { | ||||
|             $this->queryBuilder->showDatabases(); | ||||
|         } | ||||
| 
 | ||||
|         return $this; | ||||
|     } | ||||
| 
 | ||||
|     public function showTablesSqlQuery() : self | ||||
|     { | ||||
|         if ( null === $this->queryBuilder->getFragment(Query\Show::class) ) { | ||||
|             $this->queryBuilder->showTables(); | ||||
|         } | ||||
| 
 | ||||
|         return $this; | ||||
|     } | ||||
| 
 | ||||
|     public function showColumnsSqlQuery(string $table) : self | ||||
|     { | ||||
|         if ( null === $this->queryBuilder->getFragment(Query\Show::class) ) { | ||||
|             $this->queryBuilder->showColumns($table); | ||||
|         } | ||||
| 
 | ||||
|         return $this; | ||||
|     } | ||||
| } | ||||
| @ -2,7 +2,7 @@ | ||||
| 
 | ||||
| namespace Ulmus\Repository; | ||||
| 
 | ||||
| use Ulmus\{Repository, Entity}; | ||||
| use Ulmus\{EntityCollection, Repository, Entity}; | ||||
| 
 | ||||
| class SqliteRepository extends Repository { | ||||
|     use JsonConditionTrait; | ||||
| @ -19,7 +19,7 @@ class SqliteRepository extends Repository { | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     public function listColumns(? string $table = null) | ||||
|     public function listColumns(? string $table = null) : EntityCollection | ||||
|     { | ||||
|         $table ??= $this->entityResolver->tableName(); | ||||
|         $this->showColumnsSqlQuery($table); | ||||
|  | ||||
| @ -64,7 +64,7 @@ abstract class Ulmus | ||||
|     } | ||||
|      | ||||
|     public static function runSelectQuery(QueryBuilder\QueryBuilderInterface $queryBuilder, ? ConnectionAdapter $adapter = null) | ||||
|     {    | ||||
|     { | ||||
|         $dataset = static::connector($adapter)->select($queryBuilder->render(), array_merge($queryBuilder->values ?? [], $queryBuilder->parameters ?? [])); | ||||
|         $queryBuilder->reset(); | ||||
|          | ||||
| @ -74,7 +74,6 @@ abstract class Ulmus | ||||
|     public static function runQuery(QueryBuilder\QueryBuilderInterface $queryBuilder, ? ConnectionAdapter $adapter = null) | ||||
|     {    | ||||
|         $return = static::connector($adapter)->runQuery($queryBuilder->render(), array_merge($queryBuilder->values ?? [], $queryBuilder->parameters ?? [])); | ||||
| 
 | ||||
|         $queryBuilder->reset(); | ||||
|          | ||||
|         return $return; | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user