Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
36d2b16
cycle over all connections
shmax Sep 19, 2023
12b4f0a
simplify a few things
shmax Sep 20, 2023
9fd66bb
lint
shmax Sep 20, 2023
d5c571f
factor out some test class members
shmax Sep 20, 2023
3b02553
fix a few tests
shmax Sep 20, 2023
154139b
fix bad replace
shmax Sep 21, 2023
488dcc6
fix tests
shmax Sep 21, 2023
fd33d77
lint
shmax Sep 21, 2023
a9944ad
fix tests
shmax Sep 21, 2023
b2bb689
lint
shmax Sep 21, 2023
88154bf
attempted fix
shmax Sep 21, 2023
4edc6cb
try turning off db grid
shmax Sep 21, 2023
4b6acf6
try turning off db grid
shmax Sep 21, 2023
0775180
reset table data for adapter tests
shmax Sep 21, 2023
0e73373
reset table data for adapter tests
shmax Sep 21, 2023
ec7b49c
focus on sqlite
shmax Sep 21, 2023
11b5143
lint
shmax Sep 21, 2023
dd61bc0
simplify ColumnTest
shmax Sep 21, 2023
92a0446
possible fix for test
shmax Sep 21, 2023
bf76b94
lint
shmax Sep 21, 2023
96c5361
stan
shmax Sep 21, 2023
5a12260
possible fixes for mysterious test breakages
shmax Sep 22, 2023
8b7928e
tmp disable adapter tests
shmax Sep 22, 2023
0352e95
restore default
shmax Sep 22, 2023
a4f3c90
reset data
shmax Sep 22, 2023
5d2aa01
reset data
shmax Sep 22, 2023
d2a32f8
hide sql in test
shmax Sep 22, 2023
7ab50f8
fix more tests
shmax Sep 22, 2023
7d54bc5
lint
shmax Sep 22, 2023
819f6e6
rename column name
shmax Sep 22, 2023
4c75f46
fix test
shmax Sep 22, 2023
e7b8563
cleanup sequence write
shmax Sep 23, 2023
9c0d97c
use assert_sql_has
shmax Sep 23, 2023
420e980
fix table name quoting when fetching columns
shmax Sep 23, 2023
c705ab8
handle table quoting for pgsql
shmax Sep 23, 2023
36a3814
revert, try something else
shmax Sep 23, 2023
198fd9d
guard column names
shmax Sep 23, 2023
56dbbc5
restore default
shmax Sep 23, 2023
6b4f058
reset data
shmax Sep 23, 2023
c433f45
reset data
shmax Sep 23, 2023
e40e915
restore adapter test
shmax Sep 23, 2023
02cc37b
try skipping again
shmax Sep 23, 2023
e667953
remove override
shmax Sep 23, 2023
3bb106c
exit early when skipping
shmax Sep 23, 2023
d67d7d1
don't create local sqlite db in CI
shmax Sep 23, 2023
e4666a7
disable pgsql, add logging
shmax Sep 23, 2023
2365723
fix logic
shmax Sep 23, 2023
28e5ccf
use different var and restore test
shmax Sep 23, 2023
dd7f319
lint
shmax Sep 23, 2023
da57817
fix test
shmax Sep 23, 2023
d02450c
remove unused
shmax Sep 23, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ jobs:
php-version:
- 8.1
- 8.2
database:
- mysql
- pgsql
- sqlite

steps:
- name: Checkout code
Expand Down Expand Up @@ -88,6 +92,9 @@ jobs:
echo "PostgreSQL Connection String: postgres://test:test@localhost:5432/test"

- name: Run PHPUnit
env:
DATABASE: ${{ matrix.database }}
CI: true
run: |
vendor/bin/phpunit -c phpunit.xml.dist --coverage-clover=coverage.xml

Expand Down
2 changes: 2 additions & 0 deletions lib/Adapter/MysqlAdapter.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ public function limit(string $sql, int $offset = 0, int $limit = 0): string

public function query_column_info(string $table): \PDOStatement
{
$table = $this->quote_name($table);

return $this->query("SHOW COLUMNS FROM $table");
}

Expand Down
19 changes: 19 additions & 0 deletions lib/Adapter/PgsqlAdapter.php
Original file line number Diff line number Diff line change
Expand Up @@ -131,11 +131,30 @@ public function create_column(array $column): Column
return $c;
}

public function eqToken(mixed $value): string
{
if (is_array($value)) {
return 'IN(?)';
}

return '= ?';
}

public function not(): string
{
return 'NOT ';
}

public function set_encoding(string $charset): void
{
$this->query("SET NAMES '$charset'");
}

public function guard_name(string $string): string
{
return strpos($string, '-') ? $this->quote_name($string) : $string;
}

/**
* @see Connection::escapeColumns()
*
Expand Down
6 changes: 4 additions & 2 deletions lib/Adapter/SqliteAdapter.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ public function limit(string $sql, int $offset = 0, int $limit = 0)

public function query_column_info(string $table): \PDOStatement
{
$table = $this->quote_name($table);

return $this->query("pragma table_info($table)");
}

Expand Down Expand Up @@ -104,8 +106,8 @@ public function set_encoding(string $charset): void
throw new ActiveRecordException('SqliteAdapter::set_charset not supported.');
}

public function accepts_limit_and_order_for_update_and_delete(): bool
public function not(): string
{
return true;
return 'NOT ';
}
}
2 changes: 1 addition & 1 deletion lib/Column.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ class Column
public string $name = '';

/**
* The inflected name of this columns .. hyphens/spaces will be => _.
* The inflected name of this column. hyphens and spaces will become => _.
*/
public string $inflected_name;

Expand Down
23 changes: 22 additions & 1 deletion lib/Connection.php
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,17 @@ public function insert_id($sequence = null): int
return (int) $this->connection->lastInsertId($sequence);
}

public function eqToken(mixed $value): string
{
if (is_array($value)) {
return 'IN(?)';
} elseif (is_null($value)) {
return 'IS ?';
}

return '= ?';
}

/**
* Execute a raw SQL query on the database.
*
Expand Down Expand Up @@ -374,6 +385,11 @@ public function query(string $sql, array &$values = [])
return $sth;
}

public function not(): string
{
return '!';
}

/**
* Execute a query that returns maximum of one row with one field and return it.
*
Expand Down Expand Up @@ -486,12 +502,17 @@ public function next_sequence_value(string $sequence_name): ?string
*
* @param string $string string to quote
*/
public function quote_name($string): string
public function quote_name(string $string): string
{
return $string[0] === static::$QUOTE_CHARACTER || $string[strlen($string) - 1] === static::$QUOTE_CHARACTER ?
$string : static::$QUOTE_CHARACTER . $string . static::$QUOTE_CHARACTER;
}

public function guard_name(string $string): string
{
return $string;
}

/**
* Escape the column names in the where phrases
*
Expand Down
4 changes: 4 additions & 0 deletions lib/Exception/DatabaseException.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,8 @@
*/
class DatabaseException extends ActiveRecordException
{
public function __construct(string $message = '', int $code = 0, \Throwable $previous = null)
{
parent::__construct($message, $code, $previous);
}
}
12 changes: 0 additions & 12 deletions lib/Exception/ExpressionsException.php

This file was deleted.

2 changes: 1 addition & 1 deletion lib/Model.php
Original file line number Diff line number Diff line change
Expand Up @@ -364,7 +364,7 @@ public function __construct(array $attributes = [], bool $guard_attributes = tru
// initialize attributes applying defaults
if (!$instantiating_via_find) {
foreach (static::table()->columns as $name => $meta) {
$this->attributes[$meta->inflected_name] = $meta->default;
$this->attributes[$meta->inflected_name] = $meta->default ?? null;
}
}

Expand Down
11 changes: 8 additions & 3 deletions lib/Relation.php
Original file line number Diff line number Diff line change
Expand Up @@ -813,17 +813,22 @@ private function firstOrLast(int $limit = null, bool $isAscending): array
{
$options = array_merge($this->options, ['limit' => $limit ?? 1]);

$pk = $this->table()->pk;
$pk = array_map(function ($pk) {
$col = $this->table()->get_column_by_inflected_name($pk);

return $this->table()->conn->guard_name($col->name ?? '');
}, $this->table()->pk);

if (!empty($pk)) {
if (array_key_exists('order', $options)) {
if (!$isAscending) {
if (str_contains($options['order'], implode(' DESC, ', $this->table()->pk) . ' DESC')) {
if (str_contains($options['order'], implode(' DESC, ', $pk) . ' DESC')) {
$options['order'] = SQLBuilder::reverse_order((string) $options['order']);
}
}
} elseif (!array_key_exists('having', $options)) {
$command = $isAscending ? 'ASC' : 'DESC';
$options['order'] = implode(" {$command}, ", $this->table()->pk) . " {$command}";
$options['order'] = implode(" {$command}, ", $pk) . " {$command}";
}
}

Expand Down
6 changes: 2 additions & 4 deletions lib/SQLBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -120,8 +120,6 @@ public function get_where_values(): array
* @param array<string,string> $mappedNames
* @param array<string> $columns Table column names
*
* @throws Exception\ExpressionsException
*
* @return $this
*/
public function where(array $clauses=[], array $mappedNames=[], array $columns=[]): static
Expand All @@ -133,7 +131,7 @@ public function where(array $clauses=[], array $mappedNames=[], array $columns=[
$expression = $clause->to_s($this->connection, !empty($this->joins) ? $this->table : '', $mappedNames);
$expression = $this->connection->escapeColumns($expression, $columns);
$values = array_merge($values, array_flatten($clause->values()));
$inverse = $clause->negated() ? '!' : '';
$inverse = $clause->negated() ? $this->connection->not() : '';
$wrappedExpression = $inverse || count($clauses) > 1 ? '(' . $expression . ')' : $expression;
$sql .= $inverse . $wrappedExpression . ($idx < (count($clauses) - 1) ? $glue : '');
}
Expand Down Expand Up @@ -344,7 +342,7 @@ private function build_insert(): string

$e = new WhereClause($sql, [array_values($this->data)]);

return $e->to_s($this->connection);
return $e->to_s(ConnectionManager::get_connection());
}

private function build_select(): string
Expand Down
19 changes: 7 additions & 12 deletions lib/Table.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@

namespace ActiveRecord;

use ActiveRecord\Adapter\PgsqlAdapter;
use ActiveRecord\Exception\RelationshipException;
use ActiveRecord\Exception\ValidationsArgumentError;
use ActiveRecord\Relationship\AbstractRelationship;
Expand Down Expand Up @@ -364,9 +363,9 @@ public function get_column_by_inflected_name(string $inflected_name): Column|nul
return null;
}

public function get_fully_qualified_table_name(bool $quote_name = true): string
public function get_fully_qualified_table_name(): string
{
$table = $quote_name ? $this->conn->quote_name($this->table) : $this->table;
$table = $this->conn->quote_name($this->table);

if (isset($this->db_name)) {
$table = $this->conn->quote_name($this->db_name) . ".$table";
Expand Down Expand Up @@ -464,13 +463,10 @@ private function add_relationship(AbstractRelationship $relationship): void

private function get_meta_data(): void
{
// as more adapters are added probably want to do this a better way
// than using instanceof but gud enuff for now
$quote_name = !($this->conn instanceof PgsqlAdapter);

$table_name = $this->get_fully_qualified_table_name($quote_name);
$table_name = $this->table;
$conn = $this->conn;
$this->columns = Cache::get("get_meta_data-$table_name", function () use ($conn, $table_name) { return $conn->columns($table_name); });
$this->columns = Cache::get("get_meta_data-$table_name",
static fn () => $conn->columns($table_name));
}

/**
Expand Down Expand Up @@ -547,9 +543,8 @@ private function set_sequence_name(): void
return;
}

if (!($this->sequence = $this->class->getStaticPropertyValue('sequence'))) {
$this->sequence = $this->conn->get_sequence_name($this->table, $this->pk[0]);
}
$this->sequence = $this->class->getStaticPropertyValue('sequence') ??
$this->conn->get_sequence_name($this->table, $this->pk[0] ?? '');
}

private function set_associations(): void
Expand Down
34 changes: 10 additions & 24 deletions lib/WhereClause.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

namespace ActiveRecord;

use ActiveRecord\Exception\ExpressionsException;
use ActiveRecord\Exception\DatabaseException;

/**
* Templating like class for building SQL statements.
Expand Down Expand Up @@ -53,18 +53,6 @@ public function negated(): bool
return $this->negated;
}

/**
* Bind a value to the specific one based index. There must be a bind marker
* for each value bound or to_s() will throw an exception.
*/
public function bind(int $parameter_number, mixed $value): void
{
if ($parameter_number <= 0) {
throw new ExpressionsException("Invalid parameter index: $parameter_number");
}
$this->values[$parameter_number - 1] = $value;
}

/**
* Returns all the values currently bound.
*
Expand All @@ -87,7 +75,7 @@ public function expression(): array|string
* @param array<string,string> $mappedNames
* @param array<mixed> $values
*
* @throws ExpressionsException
* @throws DatabaseException
*/
public function to_s(Connection $connection, string $prependTableName = '', array $mappedNames = [],
bool $substitute=false, string $glue=' AND ', array $values=null): string
Expand All @@ -100,7 +88,11 @@ public function to_s(Connection $connection, string $prependTableName = '', arra
}

$ret = '';
$num_values = count($values);
if (1 == count($values) && is_array($values[0])) {
$num_values = count($values[0]);
} else {
$num_values = count($values);
}
$quotes = 0;

for ($i = 0, $j = 0; $i < strlen($expression); ++$i) {
Expand All @@ -109,7 +101,7 @@ public function to_s(Connection $connection, string $prependTableName = '', arra
if (self::ParameterMarker == $ch) {
if (0 == $quotes % 2) {
if ($j > $num_values - 1) {
throw new ExpressionsException("No bound parameter for index $j");
throw new DatabaseException("No bound parameter for index $j");
}
$ch = $this->substitute($connection, $expression, $values, $substitute, $i, $j++);
}
Expand Down Expand Up @@ -165,7 +157,7 @@ public static function from_underscored_string(
// map to correct name if $map was supplied
$name = $map && isset($map[$parts[$i]]) ? $map[$parts[$i]] : $parts[$i];

$expression .= $connection->quote_name($name) . $bind;
$expression .= $name . $bind;
}

return new WhereClause($expression, $conditionValues);
Expand Down Expand Up @@ -222,13 +214,7 @@ private function build_sql_from_hash(Connection $connection, array $hash, string
$name = $table . '.' . $name;
}

if (is_array($value)) {
$sql .= "$g$name IN(?)";
} elseif (is_null($value)) {
$sql .= "$g$name IS ?";
} else {
$sql .= "$g$name = ?";
}
$sql .= "$g$name " . $connection->eqToken($value);

$g = $glue;
}
Expand Down
7 changes: 5 additions & 2 deletions test/ActiveRecordCacheTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,16 @@ public function setUp($connection_name=null): void
return;
}

parent::setUp($connection_name);
Config::instance()->set_cache('memcache://localhost');
parent::setUp($connection_name);
static::setUpBeforeClass();
}

public function tearDown(): void
{
Cache::flush();
Cache::initialize();
parent::tearDown();
}

public function testDefaultExpire()
Expand All @@ -37,9 +39,10 @@ public function testExplicitDefaultExpire()

public function testCachesColumnMetaData()
{
static::resetTableData();
Author::first();

$table_name = Author::table()->get_fully_qualified_table_name(!($this->connection instanceof ActiveRecord\PgsqlAdapter));
$table_name = Author::table()->table;
$value = Cache::$adapter->read("get_meta_data-$table_name");
$this->assertTrue(is_array($value));
}
Expand Down
Loading