Remove ID col from doc table
This commit is contained in:
		
							parent
							
								
									9af41447b7
								
							
						
					
					
						commit
						1e6d984d95
					
				| @ -98,7 +98,7 @@ class Data | ||||
|             Query::whereJsonPathMatches('$2')); | ||||
|         $params = [ | ||||
|             Query::jsonbDocParam([ 'userId' => $userId ]), | ||||
|             sprintf("$.history[0].status ? (@ $op \"%s\")", RequestAction::Answered->name) | ||||
|             sprintf('$.history[0].status ? (@ %s "%s")', $op, RequestAction::Answered->name) | ||||
|         ]; | ||||
|         return self::mapToJournalRequest( | ||||
|             Document::customList($sql, $params, Request::class, Document::mapFromJson(...)), true); | ||||
|  | ||||
| @ -11,7 +11,7 @@ use PgSql\Connection; | ||||
| class Configuration | ||||
| { | ||||
|     /** @var string $connectionString The connection string to use when establishing a database connection */ | ||||
|     public static string $connectionString = ""; | ||||
|     public static string $connectionString = ''; | ||||
| 
 | ||||
|     /** @var ?Connection $pgConn The active connection */ | ||||
|     private static ?Connection $pgConn = null; | ||||
| @ -19,6 +19,9 @@ class Configuration | ||||
|     /** @var ?string $startUp The name of a function to run on first connection to the database */ | ||||
|     public static ?string $startUp = null; | ||||
| 
 | ||||
|     /** @var string $keyName The key name for document IDs (default "id") */ | ||||
|     public static string $keyName = 'id'; | ||||
| 
 | ||||
|     /** | ||||
|      * Ensure that the connection string is set, either explicitly, by environment variables, or with defaults | ||||
|      */ | ||||
|  | ||||
| @ -18,7 +18,19 @@ class Definition | ||||
|      */ | ||||
|     public static function createTable(string $name): string | ||||
|     { | ||||
|         return "CREATE TABLE IF NOT EXISTS $name (id TEXT NOT NULL PRIMARY KEY, data JSONB NOT NULL)"; | ||||
|         return "CREATE TABLE IF NOT EXISTS $name (data JSONB NOT NULL)"; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Create a statement to create a key for a document table | ||||
|      * | ||||
|      * @param string $tableName The table (or schema/table) for which a key should be created | ||||
|      * @return string A `CREATE INDEX` statement for a unique key for the document table | ||||
|      */ | ||||
|     public static function createKey(string $tableName): string | ||||
|     { | ||||
|         return sprintf('CREATE UNIQUE INDEX IF NOT EXISTS idx_%s_key ON %s ((data -> \'%s\'))', | ||||
|             self::extractTable($tableName), $tableName, Configuration::$keyName); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
| @ -30,21 +42,21 @@ class Definition | ||||
|      */ | ||||
|     public static function createIndex(string $name, DocumentIndex $type): string | ||||
|     { | ||||
|         $extraOps       = $type == DocumentIndex::Full ? '' : ' jsonb_path_ops'; | ||||
|         $schemaAndTable = explode('.', $name); | ||||
|         $tableName      = end($schemaAndTable); | ||||
|         return "CREATE INDEX IF NOT EXISTS idx_$tableName ON $name USING GIN (data$extraOps)"; | ||||
|         return sprintf('CREATE INDEX IF NOT EXISTS idx_%s ON %s USING GIN (data%s)', | ||||
|             self::extractTable($name), $name, $type == DocumentIndex::Full ? '' : ' jsonb_path_ops'); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Ensure the given document table exists | ||||
|      *  | ||||
|      * @param string $name The name of the table | ||||
|      * @param string $tableName The name of the table | ||||
|      */ | ||||
|     public static function ensureTable(string $name): void | ||||
|     public static function ensureTable(string $tableName): void | ||||
|     { | ||||
|         /** @var Result|bool $result */ | ||||
|         $result = pg_query(pg_conn(), self::createTable($name)); | ||||
|         $result = pg_query(pg_conn(), self::createTable($tableName)); | ||||
|         if ($result) pg_free_result($result); | ||||
|         $result = pg_query(pg_conn(), self::createKey($tableName)); | ||||
|         if ($result) pg_free_result($result); | ||||
|     } | ||||
| 
 | ||||
| @ -60,4 +72,16 @@ class Definition | ||||
|         $result = pg_query(pg_conn(), self::createIndex($name, $type)); | ||||
|         if ($result) pg_free_result($result); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Extract just the table name from a possible `schema.table` name | ||||
|      * | ||||
|      * @param string $name The name of the table, possibly including the schema | ||||
|      * @return string The table name | ||||
|      */ | ||||
|     private static function extractTable(string $name): string | ||||
|     { | ||||
|         $schemaAndTable = explode('.', $name); | ||||
|         return end($schemaAndTable); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -3,6 +3,7 @@ declare(strict_types=1); | ||||
| 
 | ||||
| namespace BitBadger\PgDocuments; | ||||
| 
 | ||||
| use Exception; | ||||
| use JsonMapper; | ||||
| use PgSql\Result; | ||||
| 
 | ||||
| @ -45,13 +46,17 @@ class Document | ||||
| 
 | ||||
|     /** | ||||
|      * Execute a document-focused statement that does not return results | ||||
|      *  | ||||
|      * | ||||
|      * @param string $query The query to be executed | ||||
|      * @param string $docId The ID of the document on which action should be taken | ||||
|      * @param array|object $document The array or object representing the document | ||||
|      * @throws Exception If the document's ID is null | ||||
|      */ | ||||
|     private static function executeNonQuery(string $query, string $docId, array|object $document): void | ||||
|     private static function executeNonQuery(string $query, array|object $document): void | ||||
|     { | ||||
|         $docId = is_array($document) | ||||
|             ? $document[Configuration::$keyName] | ||||
|             : get_object_vars($document)[Configuration::$keyName]; | ||||
|         if (is_null($docId)) throw new Exception('PgDocument: ID cannot be NULL'); | ||||
|         /** @var Result|bool $result */ | ||||
|         $result = pg_query_params(pg_conn(), $query, [ $docId, Query::jsonbDocParam($document) ]); | ||||
|         if ($result) pg_free_result($result); | ||||
| @ -61,24 +66,22 @@ class Document | ||||
|      * Insert a document | ||||
|      *  | ||||
|      * @param string $tableName The name of the table into which a document should be inserted | ||||
|      * @param string $docId The ID of the document to be inserted | ||||
|      * @param array|object $document The array or object representing the document | ||||
|      */ | ||||
|     public static function insert(string $tableName, string $docId, array|object $document): void | ||||
|     public static function insert(string $tableName, array|object $document): void | ||||
|     { | ||||
|         self::executeNonQuery(Query::insert($tableName), $docId, $document); | ||||
|         self::executeNonQuery(Query::insert($tableName), $document); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Save (upsert) a document | ||||
|      *  | ||||
|      * @param string $tableName The name of the table into which a document should be inserted | ||||
|      * @param string $docId The ID of the document to be inserted | ||||
|      * @param array|object $document The array or object representing the document | ||||
|      */ | ||||
|     public static function save(string $tableName, string $docId, array|object $document): void | ||||
|     public static function save(string $tableName, array|object $document): void | ||||
|     { | ||||
|         self::executeNonQuery(Query::save($tableName), $docId, $document); | ||||
|         self::executeNonQuery(Query::save($tableName), $document); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
| @ -291,24 +294,22 @@ class Document | ||||
|      * Update a full document | ||||
|      *  | ||||
|      * @param string $tableName The table in which the document should be updated | ||||
|      * @param string $docId The ID of the document to be updated | ||||
|      * @param array|object $document The document to be updated | ||||
|      */ | ||||
|     public static function updateFull(string $tableName, string $docId, array|object $document): void | ||||
|     public static function updateFull(string $tableName, array|object $document): void | ||||
|     { | ||||
|         self::executeNonQuery(Query::updateFull($tableName), $docId, $document); | ||||
|         self::executeNonQuery(Query::updateFull($tableName), $document); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Update a partial document by its ID | ||||
|      *  | ||||
|      * @param string $tableName The table in which the document should be updated | ||||
|      * @param string $docId The ID of the document to be updated | ||||
|      * @param array|object $document The partial document to be updated | ||||
|      */ | ||||
|     public static function updatePartialById(string $tableName, string $docId, array|object $document): void | ||||
|     public static function updatePartialById(string $tableName, array|object $document): void | ||||
|     { | ||||
|         self::executeNonQuery(Query::updatePartialById($tableName), $docId, $document); | ||||
|         self::executeNonQuery(Query::updatePartialById($tableName), $document); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
| @ -318,7 +319,8 @@ class Document | ||||
|      * @param array|object $criteria The JSON containment criteria | ||||
|      * @param array|object $document The document to be updated | ||||
|      */ | ||||
|     public static function updatePartialByContains(string $tableName, array|object $criteria, array|object $document): void | ||||
|     public static function updatePartialByContains(string $tableName, array|object $criteria, | ||||
|                                                    array|object $document): void | ||||
|     { | ||||
|         /** @var Result|bool $result */ | ||||
|         $result = pg_query_params(pg_conn(), Query::updatePartialByContains($tableName), | ||||
| @ -336,7 +338,7 @@ class Document | ||||
|     public static function updatePartialByJsonPath(string $tableName, string $jsonPath, array|object $document): void | ||||
|     { | ||||
|         /** @var Result|bool $result */ | ||||
|         $result = pg_query_params(pg_conn(), Query::updatePartialByContains($tableName), | ||||
|         $result = pg_query_params(pg_conn(), Query::updatePartialByJsonPath($tableName), | ||||
|             [ $jsonPath, Query::jsonbDocParam($document) ]); | ||||
|         if ($result) pg_free_result($result); | ||||
|     } | ||||
| @ -349,7 +351,7 @@ class Document | ||||
|      */ | ||||
|     public static function deleteById(string $tableName, string $docId): void | ||||
|     { | ||||
|         self::executeNonQuery(Query::deleteById($tableName), $docId, []); | ||||
|         self::executeNonQuery(Query::deleteById($tableName), [ Configuration::$keyName => $docId ]); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|  | ||||
| @ -16,7 +16,18 @@ class Query | ||||
|     { | ||||
|         return "SELECT data FROM $tableName"; | ||||
|     } | ||||
|      | ||||
| 
 | ||||
|     /** | ||||
|      * Create a `WHERE` clause fragment to implement a key check condition | ||||
|      * | ||||
|      * @param string $paramName The name of the parameter to be replaced when the query is executed | ||||
|      * @return string A `WHERE` clause fragment with the named key and parameter | ||||
|      */ | ||||
|     public static function whereById(string $paramName): string | ||||
|     { | ||||
|         return sprintf("data -> '%s' = %s", Configuration::$keyName, $paramName); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Create a `WHERE` clause fragment to implement a @> (JSON contains) condition | ||||
|      *  | ||||
| @ -50,33 +61,41 @@ class Query | ||||
|         return json_encode($it); | ||||
|     } | ||||
| 
 | ||||
|     /// Create ID and data parameters for a query
 | ||||
|     /* let docParameters<'T> docId (doc : 'T) = | ||||
|         [ "@id", Sql.string docId; "@data", jsonbDocParam doc ] | ||||
|     */ | ||||
|     /** | ||||
|      * Query to insert a document | ||||
|      *  | ||||
|      * @param string $tableName The name of the table into which the document will be inserted | ||||
|      * @return string The `INSERT` statement (with `@id` and `@data` parameters defined) | ||||
|      * @return string The `INSERT` statement (with `$1` parameter defined for the document) | ||||
|      */ | ||||
|     public static function insert(string $tableName): string | ||||
|     { | ||||
|         return "INSERT INTO $tableName (id, data) VALUES ($1, $2)"; | ||||
|         return sprintf('INSERT INTO %s (data) VALUES ($1)', $tableName); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Query to save a document, inserting it if it does not exist and updating it if it does (AKA "upsert") | ||||
|      *  | ||||
|      * @param string $tableName The name of the table into which the document will be saved | ||||
|      * @return string The `INSERT`/`ON CONFLICT DO UPDATE` statement (with `@id` and `@data` parameters defined) | ||||
|      * @return string The `INSERT`/`ON CONFLICT DO UPDATE` statement (with `$1` parameter defined for the document) | ||||
|      */ | ||||
|     public static function save(string $tableName): string | ||||
|     { | ||||
|         return "INSERT INTO $tableName (id, data) VALUES ($1, $2)
 | ||||
|                   ON CONFLICT (id) DO UPDATE SET data = EXCLUDED.data";
 | ||||
|         return sprintf('INSERT INTO %s (data) VALUES ($1) ON CONFLICT (data) DO UPDATE SET data = EXCLUDED.data', | ||||
|             $tableName); | ||||
|     } | ||||
|      | ||||
| 
 | ||||
|     /** | ||||
|      * Query to count documents in a table | ||||
|      * | ||||
|      * @param string $tableName The name of the table for which documents should be counted | ||||
|      * @param string $where The condition for which documents should be counted | ||||
|      * @return string A `SELECT` statement to obtain the count of documents for the given table | ||||
|      */ | ||||
|     private static function countQuery(string $tableName, string $where): string | ||||
|     { | ||||
|         return "SELECT COUNT(*) AS it FROM $tableName WHERE $where"; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Query to count all documents in a table | ||||
|      *  | ||||
| @ -85,7 +104,7 @@ class Query | ||||
|      */ | ||||
|     public static function countAll(string $tableName): string | ||||
|     { | ||||
|         return "SELECT COUNT(id) AS it FROM $tableName"; | ||||
|         return self::countQuery($tableName, '1 = 1'); | ||||
|     } | ||||
|      | ||||
|     /** | ||||
| @ -96,7 +115,7 @@ class Query | ||||
|      */ | ||||
|     public static function countByContains(string $tableName): string | ||||
|     { | ||||
|         return "SELECT COUNT(id) AS it FROM $tableName WHERE " . self::whereDataContains('$1'); | ||||
|         return self::countQuery($tableName, self::whereDataContains('$1')); | ||||
|     } | ||||
|      | ||||
|     /** | ||||
| @ -107,9 +126,20 @@ class Query | ||||
|      */ | ||||
|     public static function countByJsonPath(string $tableName): string | ||||
|     { | ||||
|         return "SELECT COUNT(id) AS it FROM $tableName WHERE " . self::whereJsonPathMatches('$1'); | ||||
|         return self::countQuery($tableName, self::whereJsonPathMatches('$1')); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Query to check document existence | ||||
|      * | ||||
|      * @param string $tableName The name of the table in which document existence should be checked | ||||
|      * @param string $where The criteria for which document existence should be checked | ||||
|      * @return string A `SELECT` statement to check document existence for the given criteria | ||||
|      */ | ||||
|     private static function existsQuery(string $tableName, string $where): string | ||||
|     { | ||||
|         return "SELECT EXISTS (SELECT 1 FROM $tableName WHERE $where) AS it"; | ||||
|     } | ||||
|      | ||||
|     /** | ||||
|      * Query to determine if a document exists for the given ID | ||||
|      *  | ||||
| @ -118,7 +148,7 @@ class Query | ||||
|      */ | ||||
|     public static function existsById(string $tableName): string | ||||
|     { | ||||
|         return "SELECT EXISTS (SELECT 1 FROM $tableName WHERE id = $1) AS it"; | ||||
|         return self::existsQuery($tableName, self::whereById('$1')); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
| @ -129,7 +159,7 @@ class Query | ||||
|      */ | ||||
|     public static function existsByContains(string $tableName): string | ||||
|     { | ||||
|         return "SELECT EXISTS (SELECT 1 FROM $tableName WHERE " . self::whereDataContains('$1') . ' AS it'; | ||||
|         return self::existsQuery($tableName, self::whereDataContains('$1')); | ||||
|     } | ||||
|      | ||||
|     /** | ||||
| @ -140,7 +170,7 @@ class Query | ||||
|      */ | ||||
|     public static function existsByJsonPath(string $tableName): string | ||||
|     { | ||||
|         return "SELECT EXISTS (SELECT 1 FROM $tableName WHERE " . self::whereJsonPathMatches('$1') . ' AS it'; | ||||
|         return self::existsQuery($tableName, self::whereJsonPathMatches('$1')); | ||||
|     } | ||||
|      | ||||
|     /** | ||||
| @ -151,7 +181,7 @@ class Query | ||||
|      */ | ||||
|     public static function findById(string $tableName): string | ||||
|     { | ||||
|         return self::selectFromTable($tableName) . ' WHERE id = $1'; | ||||
|         return sprintf('%s WHERE %s', self::selectFromTable($tableName), self::whereById('$1')); | ||||
|     } | ||||
|      | ||||
|     /** | ||||
| @ -162,7 +192,7 @@ class Query | ||||
|      */ | ||||
|     public static function findByContains(string $tableName): string | ||||
|     { | ||||
|         return self::selectFromTable($tableName) . ' WHERE ' . self::whereDataContains('$1'); | ||||
|         return sprintf('%s WHERE %s', self::selectFromTable($tableName), self::whereDataContains('$1')); | ||||
|     } | ||||
|      | ||||
|     /** | ||||
| @ -173,7 +203,7 @@ class Query | ||||
|      */ | ||||
|     public static function findByJsonPath(string $tableName): string | ||||
|     { | ||||
|         return self::selectFromTable($tableName) . ' WHERE ' . self::whereJsonPathMatches('$1'); | ||||
|         return sprintf('%s WHERE %s', self::selectFromTable($tableName), self::whereJsonPathMatches('$1')); | ||||
|     } | ||||
|      | ||||
|     /** | ||||
| @ -184,7 +214,19 @@ class Query | ||||
|      */ | ||||
|     public static function updateFull(string $tableName): string | ||||
|     { | ||||
|         return "UPDATE $tableName SET data = $2 WHERE id = $1"; | ||||
|         return sprintf('UPDATE %s SET data = $2 WHERE %s', $tableName, self::whereById('$1')); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Query to apply a partial update to a document | ||||
|      * | ||||
|      * @param string $tableName The name of the table in which documents should be updated | ||||
|      * @param string $where The `WHERE` clause specifying which documents should be updated | ||||
|      * @return string An `UPDATE` statement to update a partial document ($1 is ID, $2 is document) | ||||
|      */ | ||||
|     private static function updatePartial(string $tableName, string $where): string | ||||
|     { | ||||
|         return sprintf('UPDATE %s SET data = data || $2 WHERE %s', $tableName, $where); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
| @ -195,7 +237,7 @@ class Query | ||||
|      */ | ||||
|     public static function updatePartialById(string $tableName): string | ||||
|     { | ||||
|         return "UPDATE $tableName SET data = data || $2 WHERE id = $1"; | ||||
|         return self::updatePartial($tableName, self::whereById('$1')); | ||||
|     } | ||||
|      | ||||
|     /** | ||||
| @ -206,7 +248,7 @@ class Query | ||||
|      */ | ||||
|     public static function updatePartialByContains(string $tableName): string | ||||
|     { | ||||
|         return "UPDATE $tableName SET data = data || $2 WHERE " . self::whereDataContains('$1'); | ||||
|         return self::updatePartial($tableName, self::whereDataContains('$1')); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
| @ -217,7 +259,19 @@ class Query | ||||
|      */ | ||||
|     public static function updatePartialByJsonPath(string $tableName): string | ||||
|     { | ||||
|         return "UPDATE $tableName SET data = data || $2 WHERE " . self::whereJsonPathMatches('$1'); | ||||
|         return self::updatePartial($tableName, self::whereJsonPathMatches('$1')); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Query to delete documents | ||||
|      * | ||||
|      * @param string $tableName The name of the table from which documents should be deleted | ||||
|      * @param string $where The criteria by which documents should be deleted | ||||
|      * @return string A `DELETE` statement to delete documents in the specified table | ||||
|      */ | ||||
|     private static function deleteQuery(string $tableName, string $where): string | ||||
|     { | ||||
|         return "DELETE FROM $tableName WHERE $where"; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
| @ -228,7 +282,7 @@ class Query | ||||
|      */ | ||||
|     public static function deleteById(string $tableName): string | ||||
|     { | ||||
|         return "DELETE FROM $tableName WHERE id = $1"; | ||||
|         return self::deleteQuery($tableName, self::whereById('$1')); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
| @ -239,7 +293,7 @@ class Query | ||||
|      */ | ||||
|     public static function deleteByContains(string $tableName): string | ||||
|     { | ||||
|         return "DELETE FROM $tableName WHERE " . self::whereDataContains('$1'); | ||||
|         return self::deleteQuery($tableName, self::whereDataContains('$1')); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
| @ -250,6 +304,6 @@ class Query | ||||
|      */ | ||||
|     public static function deleteByJsonPath(string $tableName): string | ||||
|     { | ||||
|         return "DELETE FROM $tableName WHERE " . self::whereJsonPathMatches('$1'); | ||||
|         return self::deleteQuery($tableName, self::whereJsonPathMatches('$1')); | ||||
|     } | ||||
| } | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user