Add byContains and byJsonPath throughout
- Change to JSON Path function to work around PDO syntax quirk
This commit is contained in:
		
							parent
							
								
									9ecabbe39f
								
							
						
					
					
						commit
						7de39a41fc
					
				@ -36,4 +36,31 @@ class Count
 | 
			
		||||
        return Custom::scalar(Query\Count::byFields($tableName, $namedFields, $match),
 | 
			
		||||
            Parameters::addFields($namedFields, []), new CountMapper());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Count matching documents using a JSON containment query (`@>`; PostgreSQL only)
 | 
			
		||||
     *
 | 
			
		||||
     * @param string $tableName The name of the table in which documents should be counted
 | 
			
		||||
     * @param array|object $criteria The criteria for the JSON containment query
 | 
			
		||||
     * @return int The number of documents matching the JSON containment query
 | 
			
		||||
     * @throws DocumentException If the database mode is not PostgreSQL, or if an error occurs
 | 
			
		||||
     */
 | 
			
		||||
    public static function byContains(string $tableName, array|object $criteria): int
 | 
			
		||||
    {
 | 
			
		||||
        return Custom::scalar(Query\Count::byContains($tableName), Parameters::json(':criteria', $criteria),
 | 
			
		||||
            new CountMapper());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Count matching documents using a JSON Path match query (`@?`; PostgreSQL only)
 | 
			
		||||
     *
 | 
			
		||||
     * @param string $tableName The name of the table in which documents should be counted
 | 
			
		||||
     * @param string $path The JSON Path match string
 | 
			
		||||
     * @return int The number of documents matching the given JSON Path criteria
 | 
			
		||||
     * @throws DocumentException If the database mode is not PostgreSQL, or if an error occurs
 | 
			
		||||
     */
 | 
			
		||||
    public static function byJsonPath(string $tableName, string $path): int
 | 
			
		||||
    {
 | 
			
		||||
        return Custom::scalar(Query\Count::byJsonPath($tableName), [':path' => $path], new CountMapper());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -33,4 +33,28 @@ class Delete
 | 
			
		||||
        Custom::nonQuery(Query\Delete::byFields($tableName, $namedFields, $match),
 | 
			
		||||
            Parameters::addFields($namedFields, []));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Delete documents matching a JSON containment query (`@>`; PostgreSQL only)
 | 
			
		||||
     *
 | 
			
		||||
     * @param string $tableName The table from which documents should be deleted
 | 
			
		||||
     * @param array|object $criteria The JSON containment query values
 | 
			
		||||
     * @throws DocumentException If the database mode is not PostgreSQL, or if an error occurs
 | 
			
		||||
     */
 | 
			
		||||
    public static function byContains(string $tableName, array|object $criteria): void
 | 
			
		||||
    {
 | 
			
		||||
        Custom::nonQuery(Query\Delete::byContains($tableName), Parameters::json(':criteria', $criteria));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Delete documents matching a JSON Path match query (`@?`; PostgreSQL only)
 | 
			
		||||
     *
 | 
			
		||||
     * @param string $tableName The table from which documents should be deleted
 | 
			
		||||
     * @param string $path The JSON Path match string
 | 
			
		||||
     * @throws DocumentException If the database mode is not PostgreSQL, or if an error occurs
 | 
			
		||||
     */
 | 
			
		||||
    public static function byJsonPath(string $tableName, string $path): void
 | 
			
		||||
    {
 | 
			
		||||
        Custom::nonQuery(Query\Delete::byJsonPath($tableName), [':path' => $path]);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -37,4 +37,31 @@ class Exists
 | 
			
		||||
        return Custom::scalar(Query\Exists::byFields($tableName, $namedFields, $match),
 | 
			
		||||
            Parameters::addFields($namedFields, []), new ExistsMapper());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Determine if documents exist by a JSON containment query (`@>`; PostgreSQL only)
 | 
			
		||||
     *
 | 
			
		||||
     * @param string $tableName The name of the table in which document existence should be determined
 | 
			
		||||
     * @param array|object $criteria The criteria for the JSON containment query
 | 
			
		||||
     * @return bool True if any documents match the JSON containment query, false if not
 | 
			
		||||
     * @throws DocumentException If the database mode is not PostgreSQL, or if an error occurs
 | 
			
		||||
     */
 | 
			
		||||
    public static function byContains(string $tableName, array|object $criteria): bool
 | 
			
		||||
    {
 | 
			
		||||
        return Custom::scalar(Query\Exists::byContains($tableName), Parameters::json(':criteria', $criteria),
 | 
			
		||||
            new ExistsMapper());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Determine if documents exist by a JSON Path match query (`@?`; PostgreSQL only)
 | 
			
		||||
     *
 | 
			
		||||
     * @param string $tableName The name of the table in which document existence should be determined
 | 
			
		||||
     * @param string $path The JSON Path match string
 | 
			
		||||
     * @return bool True if any documents match the JSON Path string, false if not
 | 
			
		||||
     * @throws DocumentException If the database mode is not PostgreSQL, or if an error occurs
 | 
			
		||||
     */
 | 
			
		||||
    public static function byJsonPath(string $tableName, string $path): bool
 | 
			
		||||
    {
 | 
			
		||||
        return Custom::scalar(Query\Exists::byJsonPath($tableName), [':path' => $path], new ExistsMapper());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										62
									
								
								src/Find.php
									
									
									
									
									
								
							
							
						
						
									
										62
									
								
								src/Find.php
									
									
									
									
									
								
							@ -58,6 +58,37 @@ class Find
 | 
			
		||||
            Parameters::addFields($namedFields, []), new DocumentMapper($className));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Retrieve documents via a JSON containment query (`@>`; PostgreSQL only)
 | 
			
		||||
     *
 | 
			
		||||
     * @template TDoc The type of document to be retrieved
 | 
			
		||||
     * @param string $tableName The name of the table from which documents should be retrieved
 | 
			
		||||
     * @param array|object $criteria The criteria for the JSON containment query
 | 
			
		||||
     * @param class-string<TDoc> $className The name of the class to be retrieved
 | 
			
		||||
     * @return DocumentList<TDoc> A list of documents matching the JSON containment query
 | 
			
		||||
     * @throws DocumentException If the database mode is not PostgreSQL, or if an error occurs
 | 
			
		||||
     */
 | 
			
		||||
    public static function byContains(string $tableName, array|object $criteria, string $className): DocumentList
 | 
			
		||||
    {
 | 
			
		||||
        return Custom::list(Query\Find::byContains($tableName), Parameters::json(':criteria', $criteria),
 | 
			
		||||
            new DocumentMapper($className));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Retrieve documents via a JSON Path match query (`@?`; PostgreSQL only)
 | 
			
		||||
     *
 | 
			
		||||
     * @template TDoc The type of document to be retrieved
 | 
			
		||||
     * @param string $tableName The name of the table from which documents should be retrieved
 | 
			
		||||
     * @param string $path The JSON Path match string
 | 
			
		||||
     * @param class-string<TDoc> $className The name of the class to be retrieved
 | 
			
		||||
     * @return DocumentList<TDoc> A list of documents matching the JSON Path
 | 
			
		||||
     * @throws DocumentException If the database mode is not PostgreSQL, or if an error occurs
 | 
			
		||||
     */
 | 
			
		||||
    public static function byJsonPath(string $tableName, string $path, string $className): DocumentList
 | 
			
		||||
    {
 | 
			
		||||
        return Custom::list(Query\Find::byJsonPath($tableName), [':path' => $path], new DocumentMapper($className));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Retrieve documents via a comparison on JSON fields, returning only the first result
 | 
			
		||||
     *
 | 
			
		||||
@ -76,4 +107,35 @@ class Find
 | 
			
		||||
        return Custom::single(Query\Find::byFields($tableName, $namedFields, $match),
 | 
			
		||||
            Parameters::addFields($namedFields, []), new DocumentMapper($className));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Retrieve documents via a JSON containment query (`@>`), returning only the first result (PostgreSQL only)
 | 
			
		||||
     *
 | 
			
		||||
     * @template TDoc The type of document to be retrieved
 | 
			
		||||
     * @param string $tableName The name of the table from which documents should be retrieved
 | 
			
		||||
     * @param array|object $criteria The criteria for the JSON containment query
 | 
			
		||||
     * @param class-string<TDoc> $className The name of the class to be retrieved
 | 
			
		||||
     * @return false|TDoc The first document matching the JSON containment query if any is found, false otherwise
 | 
			
		||||
     * @throws DocumentException If the database mode is not PostgreSQL, or if an error occurs
 | 
			
		||||
     */
 | 
			
		||||
    public static function firstByContains(string $tableName, array|object $criteria, string $className): mixed
 | 
			
		||||
    {
 | 
			
		||||
        return Custom::single(Query\Find::byContains($tableName), Parameters::json(':criteria', $criteria),
 | 
			
		||||
            new DocumentMapper($className));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Retrieve documents via a JSON Path match query (`@?`), returning only the first result (PostgreSQL only)
 | 
			
		||||
     *
 | 
			
		||||
     * @template TDoc The type of document to be retrieved
 | 
			
		||||
     * @param string $tableName The name of the table from which documents should be retrieved
 | 
			
		||||
     * @param string $path The JSON Path match string
 | 
			
		||||
     * @param class-string<TDoc> $className The name of the class to be retrieved
 | 
			
		||||
     * @return false|TDoc The first document matching the JSON Path if any is found, false otherwise
 | 
			
		||||
     * @throws DocumentException If the database mode is not PostgreSQL, or if an error occurs
 | 
			
		||||
     */
 | 
			
		||||
    public static function firstByJsonPath(string $tableName, string $path, string $className): mixed
 | 
			
		||||
    {
 | 
			
		||||
        return Custom::single(Query\Find::byJsonPath($tableName), [':path' => $path], new DocumentMapper($className));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -37,4 +37,32 @@ class Patch
 | 
			
		||||
        Custom::nonQuery(Query\Patch::byFields($tableName, $namedFields, $match),
 | 
			
		||||
            Parameters::addFields($namedFields, Parameters::json(':data', $patch)));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Patch documents using a JSON containment query (`@>`; PostgreSQL only)
 | 
			
		||||
     *
 | 
			
		||||
     * @param string $tableName The table in which documents should be patched
 | 
			
		||||
     * @param array|object $criteria The JSON containment query values to match
 | 
			
		||||
     * @param array|object $patch The object with which the documents should be patched (will be JSON-encoded)
 | 
			
		||||
     * @throws DocumentException If the database mode is not PostgreSQL, or if an error occurs
 | 
			
		||||
     */
 | 
			
		||||
    public static function byContains(string $tableName, array|object $criteria, array|object $patch): void
 | 
			
		||||
    {
 | 
			
		||||
        Custom::nonQuery(Query\Patch::byContains($tableName),
 | 
			
		||||
            array_merge(Parameters::json(':criteria', $criteria), Parameters::json(':data', $patch)));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Patch documents using a JSON Path match query (`@?`; PostgreSQL only)
 | 
			
		||||
     *
 | 
			
		||||
     * @param string $tableName The table in which documents should be patched
 | 
			
		||||
     * @param string $path The JSON Path match string
 | 
			
		||||
     * @param array|object $patch The object with which the documents should be patched (will be JSON-encoded)
 | 
			
		||||
     * @throws DocumentException If the database mode is not PostgreSQL, or if an error occurs
 | 
			
		||||
     */
 | 
			
		||||
    public static function byJsonPath(string $tableName, string $path, array|object $patch): void
 | 
			
		||||
    {
 | 
			
		||||
        Custom::nonQuery(Query\Patch::byJsonPath($tableName),
 | 
			
		||||
            array_merge([':path' => $path], Parameters::json(':data', $patch)));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -75,7 +75,7 @@ class Query
 | 
			
		||||
        if (Configuration::$mode <> Mode::PgSQL) {
 | 
			
		||||
            throw new DocumentException('JSON Path matching is only supported on PostgreSQL');
 | 
			
		||||
        }
 | 
			
		||||
        return "data @? $paramName::jsonpath";
 | 
			
		||||
        return "jsonb_path_exists(data, $paramName::jsonpath)";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
 | 
			
		||||
@ -39,4 +39,34 @@ class RemoveFields
 | 
			
		||||
        Custom::nonQuery(Query\RemoveFields::byFields($tableName, $namedFields, $nameParams, $match),
 | 
			
		||||
            Parameters::addFields($namedFields, $nameParams));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Remove fields from documents via a JSON containment query (`@>`; PostgreSQL only)
 | 
			
		||||
     *
 | 
			
		||||
     * @param string $tableName The table in which documents should have fields removed
 | 
			
		||||
     * @param array|object $criteria The JSON containment query values
 | 
			
		||||
     * @param array|string[] $fieldNames The names of the fields to be removed
 | 
			
		||||
     * @throws DocumentException If the database mode is not PostgreSQL, or if an error occurs
 | 
			
		||||
     */
 | 
			
		||||
    public static function byContains(string $tableName, array|object $criteria, array $fieldNames): void
 | 
			
		||||
    {
 | 
			
		||||
        $nameParams = Parameters::fieldNames(':name', $fieldNames);
 | 
			
		||||
        Custom::nonQuery(Query\RemoveFields::byContains($tableName, $nameParams),
 | 
			
		||||
            array_merge(Parameters::json(':criteria', $criteria), $nameParams));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Remove fields from documents via a JSON Path match query (`@?`; PostgreSQL only)
 | 
			
		||||
     *
 | 
			
		||||
     * @param string $tableName The table in which documents should have fields removed
 | 
			
		||||
     * @param string $path The JSON Path match string
 | 
			
		||||
     * @param array|string[] $fieldNames The names of the fields to be removed
 | 
			
		||||
     * @throws DocumentException If the database mode is not PostgreSQL, or if an error occurs
 | 
			
		||||
     */
 | 
			
		||||
    public static function byJsonPath(string $tableName, string $path, array $fieldNames): void
 | 
			
		||||
    {
 | 
			
		||||
        $nameParams = Parameters::fieldNames(':name', $fieldNames);
 | 
			
		||||
        Custom::nonQuery(Query\RemoveFields::byJsonPath($tableName, $nameParams),
 | 
			
		||||
            array_merge([':path' => $path], $nameParams));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -44,4 +44,30 @@ class CountTest extends TestCase
 | 
			
		||||
        $count = Count::byFields(ThrowawayDb::TABLE, [Field::BT('value', 'aardvark', 'apple')]);
 | 
			
		||||
        $this->assertEquals(1, $count, 'There should have been 1 matching document');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function testByContainsSucceedsWhenDocumentsMatch(): void
 | 
			
		||||
    {
 | 
			
		||||
        $this->assertEquals(2, Count::byContains(ThrowawayDb::TABLE, ['value' => 'purple']),
 | 
			
		||||
            'There should have been 2 matching documents');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function testByContainsSucceedsWhenNoDocumentsMatch(): void
 | 
			
		||||
    {
 | 
			
		||||
        $this->assertEquals(0, Count::byContains(ThrowawayDb::TABLE, ['value' => 'magenta']),
 | 
			
		||||
            'There should have been no matching documents');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[TestDox('By JSON Path succeeds when documents match')]
 | 
			
		||||
    public function testByJsonPathSucceedsWhenDocumentsMatch(): void
 | 
			
		||||
    {
 | 
			
		||||
        $this->assertEquals(2, Count::byJsonPath(ThrowawayDb::TABLE, '$.num_value ? (@ < 5)'),
 | 
			
		||||
            'There should have been 2 matching documents');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[TestDox('By JSON Path succeeds when no documents match')]
 | 
			
		||||
    public function testByJsonPathSucceedsWhenNoDocumentsMatch(): void
 | 
			
		||||
    {
 | 
			
		||||
        $this->assertEquals(0, Count::byJsonPath(ThrowawayDb::TABLE, '$.num_value ? (@ > 100)'),
 | 
			
		||||
            'There should have been no matching documents');
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -56,4 +56,34 @@ class DeleteTest extends TestCase
 | 
			
		||||
        Delete::byFields(ThrowawayDb::TABLE, [Field::EQ('value', 'crimson')]);
 | 
			
		||||
        $this->assertEquals(5, Count::all(ThrowawayDb::TABLE), 'There should have been 5 documents remaining');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function testByContainsSucceedsWhenDocumentsAreDeleted(): void
 | 
			
		||||
    {
 | 
			
		||||
        $this->assertEquals(5, Count::all(ThrowawayDb::TABLE), 'There should have been 5 documents to start');
 | 
			
		||||
        Delete::byContains(ThrowawayDb::TABLE, ['value' => 'purple']);
 | 
			
		||||
        $this->assertEquals(3, Count::all(ThrowawayDb::TABLE), 'There should have been 3 documents remaining');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function testByContainsSucceedsWhenDocumentsAreNotDeleted(): void
 | 
			
		||||
    {
 | 
			
		||||
        $this->assertEquals(5, Count::all(ThrowawayDb::TABLE), 'There should have been 5 documents to start');
 | 
			
		||||
        Delete::byContains(ThrowawayDb::TABLE, ['target' => 'acquired']);
 | 
			
		||||
        $this->assertEquals(5, Count::all(ThrowawayDb::TABLE), 'There should have been 5 documents remaining');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[TestDox('By JSON Path succeeds when documents are deleted')]
 | 
			
		||||
    public function testByJsonPathSucceedsWhenDocumentsAreDeleted(): void
 | 
			
		||||
    {
 | 
			
		||||
        $this->assertEquals(5, Count::all(ThrowawayDb::TABLE), 'There should have been 5 documents to start');
 | 
			
		||||
        Delete::byJsonPath(ThrowawayDb::TABLE, '$.num_value ? (@ <> 0)');
 | 
			
		||||
        $this->assertEquals(1, Count::all(ThrowawayDb::TABLE), 'There should have been 1 document remaining');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[TestDox('By JSON Path succeeds when documents are not deleted')]
 | 
			
		||||
    public function testByJsonPathSucceedsWhenDocumentsAreNotDeleted(): void
 | 
			
		||||
    {
 | 
			
		||||
        $this->assertEquals(5, Count::all(ThrowawayDb::TABLE), 'There should have been 5 documents to start');
 | 
			
		||||
        Delete::byJsonPath(ThrowawayDb::TABLE, '$.num_value ? (@ < 0)');
 | 
			
		||||
        $this->assertEquals(5, Count::all(ThrowawayDb::TABLE), 'There should have been 5 documents remaining');
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -51,4 +51,30 @@ class ExistsTest extends TestCase
 | 
			
		||||
        $this->assertFalse(Exists::byFields(ThrowawayDb::TABLE, [Field::LT('nothing', 'none')]),
 | 
			
		||||
            'There should not have been any existing documents');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function testByContainsSucceedsWhenDocumentsExist(): void
 | 
			
		||||
    {
 | 
			
		||||
        $this->assertTrue(Exists::byContains(ThrowawayDb::TABLE, ['value' => 'purple']),
 | 
			
		||||
            'There should have been existing documents');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function testByContainsSucceedsWhenNoMatchingDocumentsExist(): void
 | 
			
		||||
    {
 | 
			
		||||
        $this->assertFalse(Exists::byContains(ThrowawayDb::TABLE, ['value' => 'violet']),
 | 
			
		||||
            'There should not have been existing documents');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[TestDox('By JSON Path succeeds when documents exist')]
 | 
			
		||||
    public function testByJsonPathSucceedsWhenDocumentsExist(): void
 | 
			
		||||
    {
 | 
			
		||||
        $this->assertTrue(Exists::byJsonPath(ThrowawayDb::TABLE, '$.num_value ? (@ == 10)'),
 | 
			
		||||
            'There should have been existing documents');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[TestDox('By JSON Path succeeds when no matching documents exist')]
 | 
			
		||||
    public function testByJsonPathSucceedsWhenNoMatchingDocumentsExist(): void
 | 
			
		||||
    {
 | 
			
		||||
        $this->assertFalse(Exists::byJsonPath(ThrowawayDb::TABLE, '$.num_value ? (@ == 10.1)'),
 | 
			
		||||
            'There should have been existing documents');
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -86,6 +86,40 @@ class FindTest extends TestCase
 | 
			
		||||
        $this->assertFalse($docs->hasItems(), 'There should have been no documents in the list');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function testByContainsSucceedsWhenDocumentsAreFound(): void
 | 
			
		||||
    {
 | 
			
		||||
        $docs = Find::byContains(ThrowawayDb::TABLE, ['value' => 'purple'], TestDocument::class);
 | 
			
		||||
        $this->assertNotNull($docs, 'There should have been a document list returned');
 | 
			
		||||
        $count = 0;
 | 
			
		||||
        foreach ($docs->items() as $ignored) $count++;
 | 
			
		||||
        $this->assertEquals(2, $count, 'There should have been 2 documents in the list');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function testByContainsSucceedsWhenNoDocumentsAreFound(): void
 | 
			
		||||
    {
 | 
			
		||||
        $docs = Find::byContains(ThrowawayDb::TABLE, ['value' => 'indigo'], TestDocument::class);
 | 
			
		||||
        $this->assertNotNull($docs, 'There should have been a document list returned');
 | 
			
		||||
        $this->assertFalse($docs->hasItems(), 'The document list should be empty');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[TestDox('By JSON Path succeeds when documents are found')]
 | 
			
		||||
    public function testByJsonPathSucceedsWhenDocumentsAreFound(): void
 | 
			
		||||
    {
 | 
			
		||||
        $docs = Find::byJsonPath(ThrowawayDb::TABLE, '$.num_value ? (@ > 10)', TestDocument::class);
 | 
			
		||||
        $this->assertNotNull($docs, 'There should have been a document list returned');
 | 
			
		||||
        $count = 0;
 | 
			
		||||
        foreach ($docs->items() as $ignored) $count++;
 | 
			
		||||
        $this->assertEquals(2, $count, 'There should have been 2 documents in the list');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[TestDox('By JSON Path succeeds when no documents are found')]
 | 
			
		||||
    public function testByJsonPathSucceedsWhenNoDocumentsAreFound(): void
 | 
			
		||||
    {
 | 
			
		||||
        $docs = Find::byJsonPath(ThrowawayDb::TABLE, '$.num_value ? (@ > 100)', TestDocument::class);
 | 
			
		||||
        $this->assertNotNull($docs, 'There should have been a document list returned');
 | 
			
		||||
        $this->assertFalse($docs->hasItems(), 'The document list should be empty');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function testFirstByFieldsSucceedsWhenADocumentIsFound(): void
 | 
			
		||||
    {
 | 
			
		||||
        $doc = Find::firstByFields(ThrowawayDb::TABLE, [Field::EQ('value', 'another')], TestDocument::class);
 | 
			
		||||
@ -105,4 +139,46 @@ class FindTest extends TestCase
 | 
			
		||||
        $doc = Find::firstByFields(ThrowawayDb::TABLE, [Field::EQ('value', 'absent')], TestDocument::class);
 | 
			
		||||
        $this->assertFalse($doc, 'There should not have been a document returned');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function testFirstByContainsSucceedsWhenADocumentIsFound(): void
 | 
			
		||||
    {
 | 
			
		||||
        $doc = Find::firstByContains(ThrowawayDb::TABLE, ['value' => 'FIRST!'], TestDocument::class);
 | 
			
		||||
        $this->assertNotFalse($doc, 'There should have been a document returned');
 | 
			
		||||
        $this->assertEquals('one', $doc->id, 'The incorrect document was returned');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function testFirstByContainsSucceedsWhenMultipleDocumentsAreFound(): void
 | 
			
		||||
    {
 | 
			
		||||
        $doc = Find::firstByContains(ThrowawayDb::TABLE, ['value' => 'purple'], TestDocument::class);
 | 
			
		||||
        $this->assertNotFalse($doc, 'There should have been a document returned');
 | 
			
		||||
        $this->assertContains($doc->id, ['four', 'five'], 'An incorrect document was returned');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function testFirstByContainsSucceedsWhenADocumentIsNotFound(): void
 | 
			
		||||
    {
 | 
			
		||||
        $doc = Find::firstByContains(ThrowawayDb::TABLE, ['value' => 'indigo'], TestDocument::class);
 | 
			
		||||
        $this->assertFalse($doc, 'There should not have been a document returned');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[TestDox('First by JSON Path succeeds when a document is found')]
 | 
			
		||||
    public function testFirstByJsonPathSucceedsWhenADocumentIsFound(): void
 | 
			
		||||
    {
 | 
			
		||||
        $doc = Find::firstByJsonPath(ThrowawayDb::TABLE, '$.num_value ? (@ == 10)', TestDocument::class);
 | 
			
		||||
        $this->assertEquals('two', $doc->id, 'The incorrect document was returned');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[TestDox('First by JSON Path succeeds when multiple documents are found')]
 | 
			
		||||
    public function testFirstByJsonPathSucceedsWhenMultipleDocumentsAreFound(): void
 | 
			
		||||
    {
 | 
			
		||||
        $doc = Find::firstByJsonPath(ThrowawayDb::TABLE, '$.num_value ? (@ > 10)', TestDocument::class);
 | 
			
		||||
        $this->assertNotFalse($doc, 'There should have been a document returned');
 | 
			
		||||
        $this->assertContains($doc->id, ['four', 'five'], 'An incorrect document was returned');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[TestDox('First by JSON Path succeeds when a document is not found')]
 | 
			
		||||
    public function testFirstByJsonPathSucceedsWhenADocumentIsNotFound(): void
 | 
			
		||||
    {
 | 
			
		||||
        $doc = Find::firstByJsonPath(ThrowawayDb::TABLE, '$.num_value ? (@ > 100)', TestDocument::class);
 | 
			
		||||
        $this->assertFalse($doc, 'There should not have been a document returned');
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -2,7 +2,7 @@
 | 
			
		||||
 | 
			
		||||
namespace Test\Integration\PostgreSQL;
 | 
			
		||||
 | 
			
		||||
use BitBadger\PDODocument\{Count, Field, Find, Patch};
 | 
			
		||||
use BitBadger\PDODocument\{Count, Exists, Field, Find, Patch};
 | 
			
		||||
use PHPUnit\Framework\Attributes\TestDox;
 | 
			
		||||
use PHPUnit\Framework\TestCase;
 | 
			
		||||
use Test\Integration\TestDocument;
 | 
			
		||||
@ -40,7 +40,9 @@ class PatchTest extends TestCase
 | 
			
		||||
    #[TestDox('By ID succeeds when no document is updated')]
 | 
			
		||||
    public function testByIdSucceedsWhenNoDocumentIsUpdated(): void
 | 
			
		||||
    {
 | 
			
		||||
        Patch::byId(ThrowawayDb::TABLE, 'forty-seven', ['foo' => 'green']);
 | 
			
		||||
        $id = 'forty-seven';
 | 
			
		||||
        $this->assertFalse(Exists::byId(ThrowawayDb::TABLE, $id), 'The document should not exist');
 | 
			
		||||
        Patch::byId(ThrowawayDb::TABLE, $id, ['foo' => 'green']);
 | 
			
		||||
        $this->assertTrue(true, 'The above not throwing an exception is the test');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -53,7 +55,50 @@ class PatchTest extends TestCase
 | 
			
		||||
 | 
			
		||||
    public function testByFieldsSucceedsWhenNoDocumentIsUpdated(): void
 | 
			
		||||
    {
 | 
			
		||||
        Patch::byFields(ThrowawayDb::TABLE, [Field::EQ('value', 'burgundy')], ['foo' => 'green']);
 | 
			
		||||
        $fields = [Field::EQ('value', 'burgundy')];
 | 
			
		||||
        $this->assertEquals(0, Count::byFields(ThrowawayDb::TABLE, $fields), 'There should be no matching documents');
 | 
			
		||||
        Patch::byFields(ThrowawayDb::TABLE, $fields, ['foo' => 'green']);
 | 
			
		||||
        $this->assertTrue(true, 'The above not throwing an exception is the test');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function testByContainsSucceedsWhenDocumentsAreUpdated(): void
 | 
			
		||||
    {
 | 
			
		||||
        Patch::byContains(ThrowawayDb::TABLE, ['value' => 'another'], ['num_value' => 12]);
 | 
			
		||||
        $doc = Find::firstByContains(ThrowawayDb::TABLE, ['value' => 'another'], TestDocument::class);
 | 
			
		||||
        $this->assertNotFalse($doc, 'There should have been a document returned');
 | 
			
		||||
        $this->assertEquals('two', $doc->id, 'An incorrect document was returned');
 | 
			
		||||
        $this->assertEquals(12, $doc->num_value, 'The document was not patched');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function testByContainsSucceedsWhenNoDocumentsAreUpdated(): void
 | 
			
		||||
    {
 | 
			
		||||
        $criteria = ['value' => 'updated'];
 | 
			
		||||
        $this->assertEquals(0, Count::byContains(ThrowawayDb::TABLE, $criteria),
 | 
			
		||||
            'There should be no matching documents');
 | 
			
		||||
        Patch::byContains(ThrowawayDb::TABLE, $criteria, ['sub.foo' => 'green']);
 | 
			
		||||
        $this->assertTrue(true, 'The above not throwing an exception is the test');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[TestDox('By JSON Path succeeds when documents are updated')]
 | 
			
		||||
    public function testByJsonPathSucceedsWhenDocumentsAreUpdated(): void
 | 
			
		||||
    {
 | 
			
		||||
        Patch::byJsonPath(ThrowawayDb::TABLE, '$.num_value ? (@ > 10)', ['value' => 'blue']);
 | 
			
		||||
        $docs = Find::byJsonPath(ThrowawayDb::TABLE, '$.num_value ? (@ > 10)', TestDocument::class);
 | 
			
		||||
        $this->assertNotNull($docs, 'There should have been a document list returned');
 | 
			
		||||
        $this->assertTrue($docs->hasItems(), 'The document list should not be empty');
 | 
			
		||||
        foreach ($docs->items() as $item) {
 | 
			
		||||
            $this->assertContains($item->id, ['four', 'five'], 'An incorrect document was returned');
 | 
			
		||||
            $this->assertEquals('blue', $item->value, 'The document was not patched');
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[TestDox('By JSON Path succeeds when documents are not updated')]
 | 
			
		||||
    public function testByJsonPathSucceedsWhenDocumentsAreNotUpdated(): void
 | 
			
		||||
    {
 | 
			
		||||
        $path = '$.num_value ? (@ > 100)';
 | 
			
		||||
        $this->assertEquals(0, Count::byJsonPath(ThrowawayDb::TABLE, $path),
 | 
			
		||||
            'There should be no documents matching this path');
 | 
			
		||||
        Patch::byJsonPath(ThrowawayDb::TABLE, $path, ['value' => 'blue']);
 | 
			
		||||
        $this->assertTrue(true, 'The above not throwing an exception is the test');
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -71,4 +71,57 @@ class RemoveFieldsTest extends TestCase
 | 
			
		||||
        RemoveFields::byFields(ThrowawayDb::TABLE, [Field::NE('missing', 'nope')], ['value']);
 | 
			
		||||
        $this->assertTrue(true, 'The above not throwing an exception is the test');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function testByContainsSucceedsWhenAFieldIsRemoved(): void
 | 
			
		||||
    {
 | 
			
		||||
        $criteria = ['sub' => ['foo' => 'green']];
 | 
			
		||||
        RemoveFields::byContains(ThrowawayDb::TABLE, $criteria, ['value']);
 | 
			
		||||
        $docs = Find::byContains(ThrowawayDb::TABLE, $criteria, TestDocument::class);
 | 
			
		||||
        $this->assertNotNull($docs, 'There should have been a document list returned');
 | 
			
		||||
        $this->assertTrue($docs->hasItems(), 'The document list should not have been empty');
 | 
			
		||||
        foreach ($docs->items() as $item) {
 | 
			
		||||
            $this->assertContains($item->id, ['two', 'four'], 'An incorrect document was returned');
 | 
			
		||||
            $this->assertEquals('', $item->value, 'The value field was not removed');
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function testByContainsSucceedsWhenAFieldIsNotRemoved(): void
 | 
			
		||||
    {
 | 
			
		||||
        RemoveFields::byContains(ThrowawayDb::TABLE, ['sub' => ['foo' => 'green']], ['invalid_field']);
 | 
			
		||||
        $this->assertTrue(true, 'The above not throwing an exception is the test');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function testByContainsSucceedsWhenNoDocumentIsMatched(): void
 | 
			
		||||
    {
 | 
			
		||||
        RemoveFields::byContains(ThrowawayDb::TABLE, ['value' => 'substantial'], ['num_value']);
 | 
			
		||||
        $this->assertTrue(true, 'The above not throwing an exception is the test');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[TestDox('By JSON Path succeeds when a field is removed')]
 | 
			
		||||
    public function testByJsonPathSucceedsWhenAFieldIsRemoved(): void
 | 
			
		||||
    {
 | 
			
		||||
        $path = '$.value ? (@ == "purple")';
 | 
			
		||||
        RemoveFields::byJsonPath(ThrowawayDb::TABLE, $path, ['sub']);
 | 
			
		||||
        $docs = Find::byJsonPath(ThrowawayDb::TABLE, $path, TestDocument::class);
 | 
			
		||||
        $this->assertNotNull($docs, 'There should have been a document list returned');
 | 
			
		||||
        $this->assertTrue($docs->hasItems(), 'The document list should not have been empty');
 | 
			
		||||
        foreach ($docs->items() as $item) {
 | 
			
		||||
            $this->assertContains($item->id, ['four', 'five'], 'An incorrect document was returned');
 | 
			
		||||
            $this->assertNull($item->sub, 'The sub field was not removed');
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[TestDox('By JSON Path succeeds when a field is not removed')]
 | 
			
		||||
    public function testByJsonPathSucceedsWhenAFieldIsNotRemoved(): void
 | 
			
		||||
    {
 | 
			
		||||
        RemoveFields::byJsonPath(ThrowawayDb::TABLE, '$.value ? (@ == "purple")', ['submarine']);
 | 
			
		||||
        $this->assertTrue(true, 'The above not throwing an exception is the test');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[TestDox('By JSON Path succeeds when no document is matched')]
 | 
			
		||||
    public function testByJsonPathSucceedsWhenNoDocumentIsMatched(): void
 | 
			
		||||
    {
 | 
			
		||||
        RemoveFields::byJsonPath(ThrowawayDb::TABLE, '$.value ? (@ == "mauve")', ['value']);
 | 
			
		||||
        $this->assertTrue(true, 'The above not throwing an exception is the test');
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -2,7 +2,7 @@
 | 
			
		||||
 | 
			
		||||
namespace Test\Integration\SQLite;
 | 
			
		||||
 | 
			
		||||
use BitBadger\PDODocument\{Count, Field};
 | 
			
		||||
use BitBadger\PDODocument\{Count, DocumentException, Field};
 | 
			
		||||
use PHPUnit\Framework\Attributes\TestDox;
 | 
			
		||||
use PHPUnit\Framework\TestCase;
 | 
			
		||||
 | 
			
		||||
@ -44,4 +44,17 @@ class CountTest extends TestCase
 | 
			
		||||
        $count = Count::byFields(ThrowawayDb::TABLE, [Field::BT('value', 'aardvark', 'apple')]);
 | 
			
		||||
        $this->assertEquals(1, $count, 'There should have been 1 matching document');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function testByContainsFails(): void
 | 
			
		||||
    {
 | 
			
		||||
        $this->expectException(DocumentException::class);
 | 
			
		||||
        Count::byContains('', []);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[TestDox('By JSON Path fails')]
 | 
			
		||||
    public function testByJsonPathFails(): void
 | 
			
		||||
    {
 | 
			
		||||
        $this->expectException(DocumentException::class);
 | 
			
		||||
        Count::byJsonPath('', '');
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -2,7 +2,7 @@
 | 
			
		||||
 | 
			
		||||
namespace Test\Integration\SQLite;
 | 
			
		||||
 | 
			
		||||
use BitBadger\PDODocument\{Count, Delete, Field};
 | 
			
		||||
use BitBadger\PDODocument\{Count, Delete, DocumentException, Field};
 | 
			
		||||
use PHPUnit\Framework\Attributes\TestDox;
 | 
			
		||||
use PHPUnit\Framework\TestCase;
 | 
			
		||||
 | 
			
		||||
@ -56,4 +56,17 @@ class DeleteTest extends TestCase
 | 
			
		||||
        Delete::byFields(ThrowawayDb::TABLE, [Field::EQ('value', 'crimson')]);
 | 
			
		||||
        $this->assertEquals(5, Count::all(ThrowawayDb::TABLE), 'There should have been 5 documents remaining');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function testByContainsFails(): void
 | 
			
		||||
    {
 | 
			
		||||
        $this->expectException(DocumentException::class);
 | 
			
		||||
        Delete::byContains('', []);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[TestDox('By JSON Path fails')]
 | 
			
		||||
    public function testByJsonPathFails(): void
 | 
			
		||||
    {
 | 
			
		||||
        $this->expectException(DocumentException::class);
 | 
			
		||||
        Delete::byJsonPath('', '');
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -2,7 +2,7 @@
 | 
			
		||||
 | 
			
		||||
namespace Test\Integration\SQLite;
 | 
			
		||||
 | 
			
		||||
use BitBadger\PDODocument\{Exists, Field};
 | 
			
		||||
use BitBadger\PDODocument\{DocumentException, Exists, Field};
 | 
			
		||||
use PHPUnit\Framework\Attributes\TestDox;
 | 
			
		||||
use PHPUnit\Framework\TestCase;
 | 
			
		||||
 | 
			
		||||
@ -51,4 +51,18 @@ class ExistsTest extends TestCase
 | 
			
		||||
        $this->assertFalse(Exists::byFields(ThrowawayDb::TABLE, [Field::LT('nothing', 'none')]),
 | 
			
		||||
            'There should not have been any existing documents');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function testByContainsFails(): void
 | 
			
		||||
    {
 | 
			
		||||
        $this->expectException(DocumentException::class);
 | 
			
		||||
        Exists::byContains('', []);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[TestDox('By JSON Path fails')]
 | 
			
		||||
    public function testByJsonPathFails(): void
 | 
			
		||||
    {
 | 
			
		||||
        $this->expectException(DocumentException::class);
 | 
			
		||||
        Exists::byJsonPath('', '');
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -2,7 +2,7 @@
 | 
			
		||||
 | 
			
		||||
namespace Test\Integration\SQLite;
 | 
			
		||||
 | 
			
		||||
use BitBadger\PDODocument\{Custom, Document, Field, Find};
 | 
			
		||||
use BitBadger\PDODocument\{Custom, Document, DocumentException, Field, Find};
 | 
			
		||||
use PHPUnit\Framework\Attributes\TestDox;
 | 
			
		||||
use PHPUnit\Framework\TestCase;
 | 
			
		||||
use Test\Integration\TestDocument;
 | 
			
		||||
@ -85,6 +85,19 @@ class FindTest extends TestCase
 | 
			
		||||
        $this->assertFalse($docs->hasItems(), 'There should have been no documents in the list');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function testByContainsFails(): void
 | 
			
		||||
    {
 | 
			
		||||
        $this->expectException(DocumentException::class);
 | 
			
		||||
        Find::byContains('', [], TestDocument::class);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[TestDox('By JSON Path fails')]
 | 
			
		||||
    public function testByJsonPathFails(): void
 | 
			
		||||
    {
 | 
			
		||||
        $this->expectException(DocumentException::class);
 | 
			
		||||
        Find::byJsonPath('', '', TestDocument::class);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function testFirstByFieldsSucceedsWhenADocumentIsFound(): void
 | 
			
		||||
    {
 | 
			
		||||
        $doc = Find::firstByFields(ThrowawayDb::TABLE, [Field::EQ('value', 'another')], TestDocument::class);
 | 
			
		||||
@ -104,4 +117,17 @@ class FindTest extends TestCase
 | 
			
		||||
        $doc = Find::firstByFields(ThrowawayDb::TABLE, [Field::EQ('value', 'absent')], TestDocument::class);
 | 
			
		||||
        $this->assertFalse($doc, 'There should not have been a document returned');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function testFirstByContainsFails(): void
 | 
			
		||||
    {
 | 
			
		||||
        $this->expectException(DocumentException::class);
 | 
			
		||||
        Find::firstByContains('', [], TestDocument::class);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[TestDox('First by JSON Path fails')]
 | 
			
		||||
    public function testFirstByJsonPathFails(): void
 | 
			
		||||
    {
 | 
			
		||||
        $this->expectException(DocumentException::class);
 | 
			
		||||
        Find::firstByJsonPath('', '', TestDocument::class);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -2,7 +2,7 @@
 | 
			
		||||
 | 
			
		||||
namespace Test\Integration\SQLite;
 | 
			
		||||
 | 
			
		||||
use BitBadger\PDODocument\{Count, Field, Find, Patch};
 | 
			
		||||
use BitBadger\PDODocument\{Count, DocumentException, Field, Find, Patch};
 | 
			
		||||
use PHPUnit\Framework\Attributes\TestDox;
 | 
			
		||||
use PHPUnit\Framework\TestCase;
 | 
			
		||||
use Test\Integration\TestDocument;
 | 
			
		||||
@ -56,4 +56,17 @@ class PatchTest extends TestCase
 | 
			
		||||
        Patch::byFields(ThrowawayDb::TABLE, [Field::EQ('value', 'burgundy')], ['foo' => 'green']);
 | 
			
		||||
        $this->assertTrue(true, 'The above not throwing an exception is the test');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function testByContainsFails(): void
 | 
			
		||||
    {
 | 
			
		||||
        $this->expectException(DocumentException::class);
 | 
			
		||||
        Patch::byContains('', [], []);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[TestDox('By JSON Path fails')]
 | 
			
		||||
    public function testByJsonPathFails(): void
 | 
			
		||||
    {
 | 
			
		||||
        $this->expectException(DocumentException::class);
 | 
			
		||||
        Patch::byJsonPath('', '', []);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -2,7 +2,7 @@
 | 
			
		||||
 | 
			
		||||
namespace Test\Integration\SQLite;
 | 
			
		||||
 | 
			
		||||
use BitBadger\PDODocument\{Field, Find, RemoveFields};
 | 
			
		||||
use BitBadger\PDODocument\{DocumentException, Field, Find, RemoveFields};
 | 
			
		||||
use PHPUnit\Framework\Attributes\TestDox;
 | 
			
		||||
use PHPUnit\Framework\TestCase;
 | 
			
		||||
use Test\Integration\TestDocument;
 | 
			
		||||
@ -71,4 +71,17 @@ class RemoveFieldsTest extends TestCase
 | 
			
		||||
        RemoveFields::byFields(ThrowawayDb::TABLE, [Field::NE('missing', 'nope')], ['value']);
 | 
			
		||||
        $this->assertTrue(true, 'The above not throwing an exception is the test');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function testByContainsFails(): void
 | 
			
		||||
    {
 | 
			
		||||
        $this->expectException(DocumentException::class);
 | 
			
		||||
        RemoveFields::byContains('', [], []);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[TestDox('By JSON Path fails')]
 | 
			
		||||
    public function testByJsonPathFails(): void
 | 
			
		||||
    {
 | 
			
		||||
        $this->expectException(DocumentException::class);
 | 
			
		||||
        RemoveFields::byJsonPath('', '', []);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -37,7 +37,7 @@ class CountTest extends TestCase
 | 
			
		||||
    public function testByContainsSucceedsForPostgreSQL(): void
 | 
			
		||||
    {
 | 
			
		||||
        Configuration::$mode = Mode::PgSQL;
 | 
			
		||||
        $this->assertEquals("SELECT COUNT(*) FROM the_table WHERE data @> :criteria", Count::byContains('the_table'),
 | 
			
		||||
        $this->assertEquals('SELECT COUNT(*) FROM the_table WHERE data @> :criteria', Count::byContains('the_table'),
 | 
			
		||||
            'SELECT statement not generated correctly');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -52,8 +52,8 @@ class CountTest extends TestCase
 | 
			
		||||
    public function testByJsonPathSucceedsForPostgreSQL(): void
 | 
			
		||||
    {
 | 
			
		||||
        Configuration::$mode = Mode::PgSQL;
 | 
			
		||||
        $this->assertEquals("SELECT COUNT(*) FROM a_table WHERE data @? :path::jsonpath", Count::byJsonPath('a_table'),
 | 
			
		||||
            'SELECT statement not generated correctly');
 | 
			
		||||
        $this->assertEquals('SELECT COUNT(*) FROM a_table WHERE jsonb_path_exists(data, :path::jsonpath)',
 | 
			
		||||
            Count::byJsonPath('a_table'), 'SELECT statement not generated correctly');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[TestDox('By JSON Path fails for non PostgreSQL')]
 | 
			
		||||
 | 
			
		||||
@ -53,8 +53,8 @@ class DeleteTest extends TestCase
 | 
			
		||||
    public function testByJsonPathSucceedsForPostgreSQL(): void
 | 
			
		||||
    {
 | 
			
		||||
        Configuration::$mode = Mode::PgSQL;
 | 
			
		||||
        $this->assertEquals('DELETE FROM here WHERE data @? :path::jsonpath', Delete::byJsonPath('here'),
 | 
			
		||||
            'DELETE statement not constructed correctly');
 | 
			
		||||
        $this->assertEquals('DELETE FROM here WHERE jsonb_path_exists(data, :path::jsonpath)',
 | 
			
		||||
            Delete::byJsonPath('here'), 'DELETE statement not constructed correctly');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[TestDox('By JSON Path fails for non PostgreSQL')]
 | 
			
		||||
 | 
			
		||||
@ -60,7 +60,7 @@ class ExistsTest extends TestCase
 | 
			
		||||
    public function testByJsonPathSucceedsForPostgreSQL(): void
 | 
			
		||||
    {
 | 
			
		||||
        Configuration::$mode = Mode::PgSQL;
 | 
			
		||||
        $this->assertEquals('SELECT EXISTS (SELECT 1 FROM lint WHERE data @? :path::jsonpath)',
 | 
			
		||||
        $this->assertEquals('SELECT EXISTS (SELECT 1 FROM lint WHERE jsonb_path_exists(data, :path::jsonpath))',
 | 
			
		||||
            Exists::byJsonPath('lint'), 'Existence query not generated correctly');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -54,8 +54,8 @@ class FindTest extends TestCase
 | 
			
		||||
    public function testByJsonPathSucceedsForPostgreSQL(): void
 | 
			
		||||
    {
 | 
			
		||||
        Configuration::$mode = Mode::PgSQL;
 | 
			
		||||
        $this->assertEquals('SELECT data FROM light WHERE data @? :path::jsonpath', Find::byJsonPath('light'),
 | 
			
		||||
            'SELECT query not generated correctly');
 | 
			
		||||
        $this->assertEquals('SELECT data FROM light WHERE jsonb_path_exists(data, :path::jsonpath)',
 | 
			
		||||
            Find::byJsonPath('light'), 'SELECT query not generated correctly');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[TestDox('By JSON Path fails for non PostgreSQL')]
 | 
			
		||||
 | 
			
		||||
@ -83,7 +83,7 @@ class PatchTest extends TestCase
 | 
			
		||||
    public function testByJsonPathSucceedsForPostgreSQL(): void
 | 
			
		||||
    {
 | 
			
		||||
        Configuration::$mode = Mode::PgSQL;
 | 
			
		||||
        $this->assertEquals('UPDATE that SET data = data || :data WHERE data @? :path::jsonpath',
 | 
			
		||||
        $this->assertEquals('UPDATE that SET data = data || :data WHERE jsonb_path_exists(data, :path::jsonpath)',
 | 
			
		||||
            Patch::byJsonPath('that'), 'Patch UPDATE statement is not correct');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -112,7 +112,8 @@ class RemoveFieldsTest extends TestCase
 | 
			
		||||
    public function testByJsonPathSucceedsForPostgreSQL(): void
 | 
			
		||||
    {
 | 
			
		||||
        Configuration::$mode = Mode::PgSQL;
 | 
			
		||||
        $this->assertEquals('UPDATE dessert SET data = data - :cake::text[] WHERE data @? :path::jsonpath',
 | 
			
		||||
        $this->assertEquals(
 | 
			
		||||
            'UPDATE dessert SET data = data - :cake::text[] WHERE jsonb_path_exists(data, :path::jsonpath)',
 | 
			
		||||
            RemoveFields::byJsonPath('dessert', Parameters::fieldNames(':cake', ['b', 'c'])),
 | 
			
		||||
            'UPDATE statement not correct');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -96,7 +96,7 @@ class QueryTest extends TestCase
 | 
			
		||||
    {
 | 
			
		||||
        Configuration::$mode = Mode::PgSQL;
 | 
			
		||||
        try {
 | 
			
		||||
            $this->assertEquals('data @? :path::jsonpath', Query::whereJsonPathMatches(),
 | 
			
		||||
            $this->assertEquals('jsonb_path_exists(data, :path::jsonpath)', Query::whereJsonPathMatches(),
 | 
			
		||||
                'WHERE fragment not constructed correctly');
 | 
			
		||||
        } finally {
 | 
			
		||||
            Configuration::$mode = null;
 | 
			
		||||
@ -108,7 +108,7 @@ class QueryTest extends TestCase
 | 
			
		||||
    {
 | 
			
		||||
        Configuration::$mode = Mode::PgSQL;
 | 
			
		||||
        try {
 | 
			
		||||
            $this->assertEquals('data @? :road::jsonpath', Query::whereJsonPathMatches(':road'),
 | 
			
		||||
            $this->assertEquals('jsonb_path_exists(data, :road::jsonpath)', Query::whereJsonPathMatches(':road'),
 | 
			
		||||
                'WHERE fragment not constructed correctly');
 | 
			
		||||
        } finally {
 | 
			
		||||
            Configuration::$mode = null;
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user