@@ -892,6 +892,26 @@ public function createIndex(string $collection, string $id, string $type, array
892892 $ collection = $ this ->filter ($ collection );
893893 $ id = $ this ->filter ($ id );
894894
895+ // JSONB array columns need GIN indexes for containment queries (@>).
896+ $ isArrayIndex = false ;
897+ if ($ type === Database::INDEX_KEY ) {
898+ $ metadataCollection = new Document (['$id ' => Database::METADATA ]);
899+ $ collectionDoc = $ this ->getDocument ($ metadataCollection , $ collection );
900+ if (!$ collectionDoc ->isEmpty ()) {
901+ $ collectionAttributes = \json_decode ($ collectionDoc ->getAttribute ('attributes ' , '[] ' ), true );
902+ $ arrayCount = 0 ;
903+ foreach ($ attributes as $ attr ) {
904+ foreach ($ collectionAttributes as $ collectionAttribute ) {
905+ if (\strtolower ($ collectionAttribute ['$id ' ]) === \strtolower ($ attr ) && !empty ($ collectionAttribute ['array ' ])) {
906+ $ arrayCount ++;
907+ break ;
908+ }
909+ }
910+ }
911+ $ isArrayIndex = $ arrayCount > 0 && $ arrayCount === \count ($ attributes );
912+ }
913+ }
914+
895915 foreach ($ attributes as $ i => $ attr ) {
896916 $ order = empty ($ orders [$ i ]) || Database::INDEX_FULLTEXT === $ type ? '' : $ orders [$ i ];
897917 $ isNestedPath = isset ($ indexAttributeTypes [$ attr ]) && \str_contains ($ attr , '. ' ) && $ indexAttributeTypes [$ attr ] === Database::VAR_OBJECT ;
@@ -933,13 +953,13 @@ public function createIndex(string $collection, string $id, string $type, array
933953 $ sql = "CREATE {$ sqlType } \"{$ keyName }\" ON {$ this ->getSQLTable ($ collection )}" ;
934954
935955 // Add USING clause for special index types
936- $ sql .= match ($ type ) {
937- Database::INDEX_SPATIAL => " USING GIST ( {$ attributes }) " ,
938- Database::INDEX_HNSW_EUCLIDEAN => " USING HNSW ( {$ attributes } vector_l2_ops) " ,
939- Database::INDEX_HNSW_COSINE => " USING HNSW ( {$ attributes } vector_cosine_ops) " ,
940- Database::INDEX_HNSW_DOT => " USING HNSW ( {$ attributes } vector_ip_ops) " ,
941- Database::INDEX_OBJECT => " USING GIN ( {$ attributes }) " ,
942- Database::INDEX_TRIGRAM =>
956+ $ sql .= match (true ) {
957+ $ type === Database::INDEX_SPATIAL => " USING GIST ( {$ attributes }) " ,
958+ $ type === Database::INDEX_HNSW_EUCLIDEAN => " USING HNSW ( {$ attributes } vector_l2_ops) " ,
959+ $ type === Database::INDEX_HNSW_COSINE => " USING HNSW ( {$ attributes } vector_cosine_ops) " ,
960+ $ type === Database::INDEX_HNSW_DOT => " USING HNSW ( {$ attributes } vector_ip_ops) " ,
961+ $ type === Database::INDEX_OBJECT , $ isArrayIndex => " USING GIN ( {$ attributes }) " ,
962+ $ type === Database::INDEX_TRIGRAM =>
943963 " USING GIN ( " . implode (', ' , array_map (
944964 fn ($ attr ) => "$ attr gin_trgm_ops " ,
945965 array_map (fn ($ attr ) => trim ($ attr ), explode (', ' , $ attributes ))
@@ -1937,7 +1957,7 @@ protected function getFulltextValue(string $value): string
19371957 protected function getSQLType (string $ type , int $ size , bool $ signed = true , bool $ array = false , bool $ required = false ): string
19381958 {
19391959 if ($ array === true ) {
1940- return ' JSONB ' ;
1960+ return " JSONB NOT NULL DEFAULT '[]'::jsonb " ;
19411961 }
19421962
19431963 switch ($ type ) {
@@ -2117,6 +2137,11 @@ public function getSupportForTimeouts(): bool
21172137 return true ;
21182138 }
21192139
2140+ public function getSupportForCastIndexArray (): bool
2141+ {
2142+ return true ;
2143+ }
2144+
21202145 /**
21212146 * Does the adapter handle Query Array Overlaps?
21222147 *
@@ -2688,12 +2713,12 @@ protected function getOperatorSQL(string $column, Operator $operator, int &$bind
26882713 case Operator::TYPE_ARRAY_APPEND :
26892714 $ bindKey = "op_ {$ bindIndex }" ;
26902715 $ bindIndex ++;
2691- return "{$ quotedColumn } = COALESCE( {$ columnRef }, '[]'::jsonb) || :$ bindKey::jsonb " ;
2716+ return "{$ quotedColumn } = {$ columnRef } || : $ bindKey::jsonb " ;
26922717
26932718 case Operator::TYPE_ARRAY_PREPEND :
26942719 $ bindKey = "op_ {$ bindIndex }" ;
26952720 $ bindIndex ++;
2696- return "{$ quotedColumn } = : $ bindKey::jsonb || COALESCE( {$ columnRef }, '[]'::jsonb) " ;
2721+ return "{$ quotedColumn } = : $ bindKey::jsonb || {$ columnRef }" ;
26972722
26982723 case Operator::TYPE_ARRAY_UNIQUE :
26992724 return "{$ quotedColumn } = COALESCE((
0 commit comments