Skip to content

Commit ac7cf73

Browse files
committed
Added test coverage
1 parent d50072c commit ac7cf73

File tree

5 files changed

+445
-62
lines changed

5 files changed

+445
-62
lines changed

src/Schema/Collections/Column_Collection.php

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,29 @@ public function offsetSet( $offset, $value ): void {
8484
* @return ?Column
8585
*/
8686
public function get( string $key ): ?Column {
87-
return $this->offsetGet( $key );
87+
foreach ( $this->resources as $column ) {
88+
if ( $column->get_name() === $key ) {
89+
return $column;
90+
}
91+
}
92+
93+
return null;
94+
}
95+
96+
/**
97+
* Gets the names from the collection.
98+
*
99+
* @since TBD
100+
*
101+
* @return array<string>
102+
*/
103+
public function get_names(): array {
104+
return array_map(
105+
function ( Column $column ) {
106+
return $column->get_name();
107+
},
108+
$this->resources
109+
);
88110
}
89111

90112
/**

src/Schema/Tables/Contracts/Table.php

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,6 @@ abstract class Table implements Table_Interface {
4848
*/
4949
protected static $schema_slug;
5050

51-
/**
52-
* @var string The field that uniquely identifies a row in the table.
53-
*/
54-
protected static $uid_column = '';
55-
5651
/**
5752
* Ordered collection of table update methods.
5853
*

src/Schema/Tables/Table_Schema.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ protected function validate_indexes(): void {
135135
throw new RuntimeException( 'Primary key already set. Only one primary key per table is allowed.' );
136136
}
137137

138-
$this->primary_key = new Primary_Key( $index_column->get_name() );
138+
$this->primary_key = ( new Primary_Key( $index_column->get_name() ) )->set_columns( $index_column->get_name() )->set_table_name( $this->get_table_name() );
139139
$indexes[ $index_column->get_name() ] = Index::TYPE_PRIMARY;
140140
continue;
141141
}
@@ -156,7 +156,7 @@ protected function validate_indexes(): void {
156156
throw new RuntimeException( 'Primary key already set. Only one primary key per table is allowed.' );
157157
}
158158

159-
$this->primary_key = new Primary_Key( $index->get_name() );
159+
$this->primary_key = $index;
160160
}
161161

162162
$indexes[ $index->get_name() ] = $index->get_type();

src/Schema/Traits/Custom_Table_Query_Methods.php

Lines changed: 73 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ trait Custom_Table_Query_Methods {
3939
*
4040
* @return Generator<array<string, mixed>> The rows from the table.
4141
*/
42-
public static function fetch_all( int $batch_size = 50, string $output = OBJECT, string $where_clause = '', string $order_by = '' ): Generator {
42+
protected static function fetch_all( int $batch_size = 50, string $output = OBJECT, string $where_clause = '', string $order_by = '' ): Generator {
4343
$fetched = 0;
4444
$total = null;
4545
$offset = 0;
@@ -50,18 +50,20 @@ public static function fetch_all( int $batch_size = 50, string $output = OBJECT,
5050

5151
$order_by = $order_by ?: implode( ', ', array_map( fn( $column ) => "{$column} ASC", $primary_columns ) );
5252

53+
$query = $database::prepare(
54+
"SELECT * FROM %i {$where_clause} ORDER BY {$order_by} LIMIT %d, %d",
55+
static::table_name( true ),
56+
$offset,
57+
$batch_size
58+
);
59+
5360
$batch = $database::get_results(
54-
$database::prepare(
55-
"SELECT * FROM %i {$where_clause} ORDER BY {$order_by} LIMIT %d, %d",
56-
static::table_name( true ),
57-
$offset,
58-
$batch_size
59-
),
61+
$query,
6062
$output
6163
);
6264

6365
// We need to get the total number of rows, only after the first batch.
64-
$total ??= $database::get_var( "SELECT COUNT(*) FROM %i {$where_clause}", static::table_name( true ) );
66+
$total ??= $database::get_var( $database::prepare( "SELECT COUNT(*) FROM %i {$where_clause}", static::table_name( true ) ) );
6567
$fetched += count( $batch );
6668

6769
$offset += $batch_size;
@@ -70,6 +72,25 @@ public static function fetch_all( int $batch_size = 50, string $output = OBJECT,
7072
} while ( $fetched < $total );
7173
}
7274

75+
/**
76+
* Fetches all the rows from the table using a batched query.
77+
*
78+
* @since TBD
79+
*
80+
* @param int $batch_size The number of rows to fetch per batch.
81+
* @param string $where_clause The optional WHERE clause to use.
82+
* @param string $order_by The optional ORDER BY clause to use.
83+
*
84+
* @return Generator<array<string, mixed>> The rows from the table.
85+
*/
86+
public static function get_all( int $batch_size = 50, string $where_clause = '', string $order_by = '' ): Generator {
87+
$batch = static::fetch_all( $batch_size, ARRAY_A, $where_clause, $order_by );
88+
89+
foreach ( $batch as $row ) {
90+
yield static::transform_from_array( static::amend_value_types( $row ) );
91+
}
92+
}
93+
7394
/**
7495
* Inserts a single row into the table.
7596
*
@@ -204,6 +225,7 @@ function ( $c ) use ( $prepared_ids ) {
204225
* @return array<string> The prepared statements and values.
205226
*/
206227
protected static function prepare_statements_values( array $entries ): array {
228+
$database = Config::get_db();
207229
$columns = array_keys( $entries[0] );
208230
$prepared_columns = implode(
209231
', ',
@@ -215,7 +237,7 @@ protected static function prepare_statements_values( array $entries ): array {
215237
$prepared_values = implode(
216238
', ',
217239
array_map(
218-
static fn ( array $entry ) => '(' . implode( ', ', array_map( static fn( $e ) => DB::prepare( '%s', $e instanceof DateTimeInterface ? $e->format( 'Y-m-d H:i:s' ) : $e ), $entry ) ) . ')',
240+
static fn ( array $entry ) => '(' . implode( ', ', array_map( static fn( $e ) => $database::prepare( '%s', $e instanceof DateTimeInterface ? $e->format( 'Y-m-d H:i:s' ) : $e ), $entry ) ) . ')',
219241
$entries
220242
)
221243
);
@@ -235,7 +257,7 @@ protected static function prepare_statements_values( array $entries ): array {
235257
*
236258
* @return Generator<array<string, mixed>> The rows from the table.
237259
*/
238-
public static function fetch_all_where( string $where_clause, int $batch_size = 50, string $output = OBJECT, string $order_by = '' ): Generator {
260+
protected static function fetch_all_where( string $where_clause, int $batch_size = 50, string $output = OBJECT, string $order_by = '' ): Generator {
239261
return static::fetch_all( $batch_size, $output, $where_clause, $order_by );
240262
}
241263

@@ -249,7 +271,7 @@ public static function fetch_all_where( string $where_clause, int $batch_size =
249271
*
250272
* @return array|object|null The row from the table, or `null` if no row was found.
251273
*/
252-
public static function fetch_first_where( string $where_clause, string $output = OBJECT ) {
274+
protected static function fetch_first_where( string $where_clause, string $output = OBJECT ) {
253275
$database = Config::get_db();
254276

255277
return $database::get_row(
@@ -297,7 +319,7 @@ public static function update_many( array $entries ): bool {
297319
$database = Config::get_db();
298320

299321
$queries = [];
300-
$columns = array_keys( static::get_columns() );
322+
$columns = static::get_columns()->get_names();
301323
foreach ( $entries as $entry ) {
302324
$uid = $entry[ $uid_column ] ?? '';
303325

@@ -373,7 +395,7 @@ public static function paginate( array $args, int $per_page = 20, int $page = 1,
373395
$orderby = $args['orderby'] ?? static::uid_column();
374396
$order = strtoupper( $args['order'] ?? 'ASC' );
375397

376-
if ( ! in_array( $orderby, array_keys( static::get_columns() ), true ) ) {
398+
if ( ! in_array( $orderby, static::get_columns()->get_names(), true ) ) {
377399
$orderby = static::uid_column();
378400
}
379401

@@ -409,7 +431,7 @@ public static function paginate( array $args, int $per_page = 20, int $page = 1,
409431
$output
410432
);
411433

412-
$results = array_map( fn( $result ) => self::amend_value_types( $result ), $results );
434+
$results = array_map( fn( $result ) => static::transform_from_array( self::amend_value_types( $result ) ), $results );
413435

414436
/**
415437
* Fires after the results of the query are fetched.
@@ -461,18 +483,18 @@ protected static function build_where_from_args( array $args = [] ): string {
461483
if ( $search ) {
462484
$searchable_columns = static::get_searchable_columns();
463485

464-
if ( ! empty( $searchable_columns ) ) {
486+
if ( $searchable_columns ) {
465487
$search_where = [];
466488

467489
foreach ( $searchable_columns as $column ) {
468-
$search_where[] = $database::prepare( "{$joined_prefix}{$column} LIKE %s", '%' . $database::esc_like( $search ) . '%' );
490+
$search_where[] = $database::prepare( "{$joined_prefix}{$column->get_name()} LIKE %s", '%' . $database::esc_like( $search ) . '%' );
469491
}
470492

471493
$where[] = '(' . implode( ' OR ', $search_where ) . ')';
472494
}
473495
}
474496

475-
$columns = array_keys( static::get_columns() );
497+
$columns = static::get_columns()->get_names();
476498

477499
foreach ( $args as $arg ) {
478500
if ( ! is_array( $arg ) ) {
@@ -556,9 +578,9 @@ protected static function get_join_parts( string $join_table, string $join_condi
556578

557579
$join_condition = array_map( 'trim', explode( '=', $join_condition, 2 ) );
558580

559-
$secondary_table_columns = array_keys( $join_table::get_columns() );
581+
$secondary_table_columns = $join_table::get_columns()->get_names();
560582

561-
$both_table_columns = array_merge( array_keys( static::get_columns() ), $secondary_table_columns );
583+
$both_table_columns = array_merge( static::get_columns()->get_names(), $secondary_table_columns );
562584

563585
if ( ! in_array( $join_condition[0], $both_table_columns, true ) || ! in_array( $join_condition[1], $both_table_columns, true ) ) {
564586
throw new InvalidArgumentException( 'The join condition must contain valid columns.' );
@@ -590,20 +612,23 @@ protected static function get_join_parts( string $join_table, string $join_condi
590612
*
591613
* @since TBD
592614
*
593-
* @param string $column The column to get the models by.
594-
* @param mixed $value The value to get the models by.
595-
* @param int $limit The limit of models to return.
615+
* @param string $column The column to get the models by.
616+
* @param mixed $value The value to get the models by.
617+
* @param string $operator The operator to use.
618+
* @param int $limit The limit of models to return.
596619
*
597620
* @return mixed[] The models, or an empty array if no models are found.
598621
*
599622
* @throws InvalidArgumentException If the column does not exist.
600623
*/
601-
public static function get_all_by( string $column, $value, int $limit = 50 ): ?array{
624+
public static function get_all_by( string $column, $value, string $operator = '=', int $limit = 50 ): ?array{
602625
[ $value, $placeholder ] = self::prepare_value_for_query( $column, $value );
603626

627+
$operator = strtoupper( $operator );
628+
604629
$database = Config::get_db();
605630
$results = [];
606-
foreach ( static::fetch_all_where( $database::prepare( "WHERE {$column} = {$placeholder}", $value ), $limit, ARRAY_A ) as $task_array ) {
631+
foreach ( static::fetch_all_where( $database::prepare( "WHERE {$column} {$operator} {$placeholder}", $value ), $limit, ARRAY_A ) as $task_array ) {
607632
if ( empty( $task_array[ static::uid_column() ] ) ) {
608633
continue;
609634
}
@@ -654,13 +679,16 @@ public static function get_first_by( string $column, $value ) {
654679
private static function prepare_value_for_query( string $column, $value ): array {
655680
$columns = static::get_columns();
656681

657-
if ( ! isset( $columns[ $column ] ) ) {
682+
/** @var ?Column $column */
683+
$column = $columns->get( $column );
684+
685+
if ( ! $column ) {
658686
throw new InvalidArgumentException( "Column $column does not exist." );
659687
}
660688

661-
$column_type = $columns[ $column ]['php_type'];
689+
$column_type = $column->get_php_type();
662690

663-
switch ( $column_type ) {
691+
switch ( $column->get_php_type() ) {
664692
case Column::PHP_TYPE_INT:
665693
case Column::PHP_TYPE_BOOL:
666694
$value = is_array( $value ) ? array_map( fn( $v ) => (int) $v, $value ) : (int) $value;
@@ -727,21 +755,25 @@ public static function operators(): array {
727755
* @return array<string, mixed> The amended data.
728756
*
729757
* @throws InvalidArgumentException If the column type is unsupported.
758+
* @throws InvalidArgumentException If the datetime value format is invalid.
730759
*/
731760
private static function amend_value_types( array $data ): array {
732761
$columns = static::get_columns();
762+
$column_names = $columns->get_names();
733763
foreach ( $data as $column => $value ) {
734-
if ( ! isset( $columns[ $column ] ) ) {
764+
if ( ! in_array( $column, $column_names, true ) ) {
735765
continue;
736766
}
737767

738-
$column_data = $columns[ $column ];
768+
$column_object = $columns->get( $column );
739769

740-
if ( ! empty( $column_data['nullable'] ) && null === $value ) {
770+
if ( $column_object->get_nullable() && null === $value ) {
741771
continue;
742772
}
743773

744-
switch ( $column_data['php_type'] ) {
774+
$column_php_type = $column_object->get_php_type();
775+
776+
switch ( $column_php_type ) {
745777
case Column::PHP_TYPE_INT:
746778
$data[ $column ] = (int) $value;
747779
break;
@@ -765,9 +797,18 @@ private static function amend_value_types( array $data ): array {
765797
}
766798

767799
$data[ $column ] = $instance::createFromFormat( 'Y-m-d H:i:s', $value );
800+
801+
if ( ! $data[ $column ] instanceof DateTimeInterface ) {
802+
$data[ $column ] = $instance::createFromFormat( 'Y-m-d', $value );
803+
}
804+
805+
if ( ! $data[ $column ] instanceof DateTimeInterface ) {
806+
throw new InvalidArgumentException( "Invalid datetime value format: {$value}." );
807+
}
808+
768809
break;
769810
default:
770-
throw new InvalidArgumentException( "Unsupported column type: {$column_data['php_type']}." );
811+
throw new InvalidArgumentException( "Unsupported column type: {$column_php_type}." );
771812
}
772813
}
773814

0 commit comments

Comments
 (0)