Files
pdo-document/src/Query/Definition.php
Daniel J. Summers d067f8983f Changes for beta10 (#5)
- Add In/InArray support
- Add ORDER BY support for `Find` functions
- Update dependencies
- Implement fixes identified via static analysis

Reviewed-on: #5
2024-09-27 02:15:00 +00:00

99 lines
3.8 KiB
PHP

<?php
/**
* @author Daniel J. Summers <daniel@bitbadger.solutions>
* @license MIT
*/
declare(strict_types=1);
namespace BitBadger\PDODocument\Query;
use BitBadger\PDODocument\{Configuration, DocumentException, DocumentIndex, Mode};
use Exception;
/**
* Queries to define tables and indexes
*/
class Definition
{
/**
* SQL statement to create a document table
*
* @param string $name The name of the table (including schema, if applicable)
* @return string The CREATE TABLE statement for the document table
* @throws Exception If the database mode has not been set
*/
public static function ensureTable(string $name): string
{
$dataType = match (Configuration::mode('make create table statement')) {
Mode::PgSQL => 'JSONB',
Mode::SQLite => 'TEXT',
};
return "CREATE TABLE IF NOT EXISTS $name (data $dataType NOT NULL)";
}
/**
* Split a schema and table name
*
* @param string $tableName The name of the table, possibly including the schema
* @return array|string[] An array with the schema at index 0 and the table name at index 1
*/
private static function splitSchemaAndTable(string $tableName): array
{
$parts = explode('.', $tableName);
return sizeof($parts) === 1 ? ["", $tableName] : [$parts[0], $parts[1]];
}
/**
* SQL statement to create an index on one or more fields in a JSON document
*
* @param string $tableName The name of the table which should be indexed
* @param string $indexName The name of the index to create
* @param string[] $fields An array of fields to be indexed; may contain direction (ex. 'salary DESC')
* @return string The CREATE INDEX statement to ensure the index exists
*/
public static function ensureIndexOn(string $tableName, string $indexName, array $fields): string
{
[, $tbl] = self::splitSchemaAndTable($tableName);
$jsonFields = implode(', ', array_map(function (string $field) {
$parts = explode(' ', $field);
$fieldName = sizeof($parts) === 1 ? $field : $parts[0];
$direction = sizeof($parts) < 2 ? "" : " $parts[1]";
return "(data->>'$fieldName')$direction";
}, $fields));
return "CREATE INDEX IF NOT EXISTS idx_{$tbl}_$indexName ON $tableName ($jsonFields)";
}
/**
* SQL statement to create a key index for a document table
*
* @param string $tableName The name of the table whose key should be ensured
* @return string The CREATE INDEX statement to ensure the key index exists
*/
public static function ensureKey(string $tableName): string
{
return str_replace('INDEX', 'UNIQUE INDEX', self::ensureIndexOn($tableName, 'key', [Configuration::$idField]));
}
/**
* Create a document-wide index on a table (PostgreSQL only)
*
* @param string $tableName The name of the table on which the document index should be created
* @param DocumentIndex $indexType The type of index to be created
* @return string The SQL statement to create an index on JSON documents in the specified table
* @throws Exception|DocumentException If the database mode is not PostgreSQL
*/
public static function ensureDocumentIndexOn(string $tableName, DocumentIndex $indexType): string
{
if (Configuration::mode() <> Mode::PgSQL) {
throw new DocumentException('Document indexes are only supported on PostgreSQL');
}
[, $tbl] = self::splitSchemaAndTable($tableName);
$extraOps = match ($indexType) {
DocumentIndex::Full => '',
DocumentIndex::Optimized => ' jsonb_path_ops',
};
return "CREATE INDEX IF NOT EXISTS idx_{$tbl}_document ON $tableName USING GIN (data$extraOps)";
}
}