@@ -49,6 +49,9 @@ class Database
4949 public const VAR_ID = 'id ' ;
5050 public const VAR_UUID7 = 'uuid7 ' ;
5151
52+ // object type
53+ public const VAR_OBJECT = 'object ' ;
54+
5255 // Vector types
5356 public const VAR_VECTOR = 'vector ' ;
5457
@@ -67,11 +70,20 @@ class Database
6770 self ::VAR_POLYGON
6871 ];
6972
73+ // All types which requires filters
74+ public const ATTRIBUTE_FILTER_TYPES = [
75+ ...self ::SPATIAL_TYPES ,
76+ self ::VAR_VECTOR ,
77+ self ::VAR_OBJECT ,
78+ self ::VAR_DATETIME
79+ ];
80+
7081 // Index Types
7182 public const INDEX_KEY = 'key ' ;
7283 public const INDEX_FULLTEXT = 'fulltext ' ;
7384 public const INDEX_UNIQUE = 'unique ' ;
7485 public const INDEX_SPATIAL = 'spatial ' ;
86+ public const INDEX_OBJECT = 'object ' ;
7587 public const INDEX_HNSW_EUCLIDEAN = 'hnsw_euclidean ' ;
7688 public const INDEX_HNSW_COSINE = 'hnsw_cosine ' ;
7789 public const INDEX_HNSW_DOT = 'hnsw_dot ' ;
@@ -633,6 +645,35 @@ function (?string $value) {
633645 return is_array ($ decoded ) ? $ decoded : $ value ;
634646 }
635647 );
648+
649+ self ::addFilter (
650+ Database::VAR_OBJECT ,
651+ /**
652+ * @param mixed $value
653+ * @return mixed
654+ */
655+ function (mixed $ value ) {
656+ if (!\is_array ($ value )) {
657+ return $ value ;
658+ }
659+
660+ return \json_encode ($ value );
661+ },
662+ /**
663+ * @param string|null $value
664+ * @return array|null
665+ */
666+ function (?string $ value ) {
667+ if (is_null ($ value )) {
668+ return null ;
669+ }
670+ if (!is_string ($ value )) {
671+ return $ value ;
672+ }
673+ $ decoded = json_decode ($ value , true );
674+ return is_array ($ decoded ) ? $ decoded : $ value ;
675+ }
676+ );
636677 }
637678
638679 /**
@@ -1557,7 +1598,7 @@ public function delete(?string $database = null): bool
15571598 public function createCollection (string $ id , array $ attributes = [], array $ indexes = [], ?array $ permissions = null , bool $ documentSecurity = true ): Document
15581599 {
15591600 foreach ($ attributes as &$ attribute ) {
1560- if (in_array ($ attribute ['type ' ], Database:: SPATIAL_TYPES ) || $ attribute [ ' type ' ] === Database:: VAR_VECTOR ) {
1601+ if (in_array ($ attribute ['type ' ], self :: ATTRIBUTE_FILTER_TYPES ) ) {
15611602 $ existingFilters = $ attribute ['filters ' ] ?? [];
15621603 if (!is_array ($ existingFilters )) {
15631604 $ existingFilters = [$ existingFilters ];
@@ -1644,6 +1685,7 @@ public function createCollection(string $id, array $attributes = [], array $inde
16441685 $ this ->adapter ->getSupportForAttributes (),
16451686 $ this ->adapter ->getSupportForMultipleFulltextIndexes (),
16461687 $ this ->adapter ->getSupportForIdenticalIndexes (),
1688+ $ this ->adapter ->getSupportForObject (),
16471689 );
16481690 foreach ($ indexes as $ index ) {
16491691 if (!$ validator ->isValid ($ index )) {
@@ -1963,11 +2005,8 @@ public function createAttribute(string $collection, string $id, string $type, in
19632005 if ($ collection ->isEmpty ()) {
19642006 throw new NotFoundException ('Collection not found ' );
19652007 }
1966- if (in_array ($ type , Database::SPATIAL_TYPES )) {
1967- $ filters [] = $ type ;
1968- $ filters = array_unique ($ filters );
1969- }
1970- if ($ type === Database::VAR_VECTOR ) {
2008+
2009+ if (in_array ($ type , self ::ATTRIBUTE_FILTER_TYPES )) {
19712010 $ filters [] = $ type ;
19722011 $ filters = array_unique ($ filters );
19732012 }
@@ -2252,6 +2291,17 @@ private function validateAttribute(
22522291 case self ::VAR_DATETIME :
22532292 case self ::VAR_RELATIONSHIP :
22542293 break ;
2294+ case self ::VAR_OBJECT :
2295+ if (!$ this ->adapter ->getSupportForObject ()) {
2296+ throw new DatabaseException ('Object attributes are not supported ' );
2297+ }
2298+ if (!empty ($ size )) {
2299+ throw new DatabaseException ('Size must be empty for object attributes ' );
2300+ }
2301+ if (!empty ($ array )) {
2302+ throw new DatabaseException ('Object attributes cannot be arrays ' );
2303+ }
2304+ break ;
22552305 case self ::VAR_POINT :
22562306 case self ::VAR_LINESTRING :
22572307 case self ::VAR_POLYGON :
@@ -2310,6 +2360,9 @@ private function validateAttribute(
23102360 if ($ this ->adapter ->getSupportForSpatialAttributes ()) {
23112361 \array_push ($ supportedTypes , ...self ::SPATIAL_TYPES );
23122362 }
2363+ if ($ this ->adapter ->getSupportForObject ()) {
2364+ $ supportedTypes [] = self ::VAR_OBJECT ;
2365+ }
23132366 throw new DatabaseException ('Unknown attribute type: ' . $ type . '. Must be one of ' . implode (', ' , $ supportedTypes ));
23142367 }
23152368
@@ -2360,7 +2413,7 @@ protected function validateDefaultTypes(string $type, mixed $default): void
23602413
23612414 if ($ defaultType === 'array ' ) {
23622415 // Spatial types require the array itself
2363- if (!in_array ($ type , Database::SPATIAL_TYPES )) {
2416+ if (!in_array ($ type , Database::SPATIAL_TYPES ) && $ type != Database:: VAR_OBJECT ) {
23642417 foreach ($ default as $ value ) {
23652418 $ this ->validateDefaultTypes ($ type , $ value );
23662419 }
@@ -2685,7 +2738,17 @@ public function updateAttribute(string $collection, string $id, ?string $type =
26852738 throw new DatabaseException ('Size must be empty ' );
26862739 }
26872740 break ;
2688-
2741+ case self ::VAR_OBJECT :
2742+ if (!$ this ->adapter ->getSupportForObject ()) {
2743+ throw new DatabaseException ('Object attributes are not supported ' );
2744+ }
2745+ if (!empty ($ size )) {
2746+ throw new DatabaseException ('Size must be empty for object attributes ' );
2747+ }
2748+ if (!empty ($ array )) {
2749+ throw new DatabaseException ('Object attributes cannot be arrays ' );
2750+ }
2751+ break ;
26892752 case self ::VAR_POINT :
26902753 case self ::VAR_LINESTRING :
26912754 case self ::VAR_POLYGON :
@@ -2860,6 +2923,7 @@ public function updateAttribute(string $collection, string $id, ?string $type =
28602923 $ this ->adapter ->getSupportForAttributes (),
28612924 $ this ->adapter ->getSupportForMultipleFulltextIndexes (),
28622925 $ this ->adapter ->getSupportForIdenticalIndexes (),
2926+ $ this ->adapter ->getSupportForObject (),
28632927 );
28642928
28652929 foreach ($ indexes as $ index ) {
@@ -4044,8 +4108,14 @@ public function createIndex(string $collection, string $id, string $type, array
40444108 }
40454109 break ;
40464110
4111+ case self ::INDEX_OBJECT :
4112+ if (!$ this ->adapter ->getSupportForObject ()) {
4113+ throw new DatabaseException ('Object indexes are not supported ' );
4114+ }
4115+ break ;
4116+
40474117 default :
4048- throw new DatabaseException ('Unknown index type: ' . $ type . '. Must be one of ' . Database::INDEX_KEY . ', ' . Database::INDEX_UNIQUE . ', ' . Database::INDEX_FULLTEXT . ', ' . Database::INDEX_SPATIAL . ', ' . Database::INDEX_HNSW_EUCLIDEAN . ', ' . Database::INDEX_HNSW_COSINE . ', ' . Database::INDEX_HNSW_DOT );
4118+ throw new DatabaseException ('Unknown index type: ' . $ type . '. Must be one of ' . Database::INDEX_KEY . ', ' . Database::INDEX_UNIQUE . ', ' . Database::INDEX_FULLTEXT . ', ' . Database::INDEX_SPATIAL . ', ' . Database::INDEX_OBJECT . ' , ' . Database:: INDEX_HNSW_EUCLIDEAN . ', ' . Database::INDEX_HNSW_COSINE . ', ' . Database::INDEX_HNSW_DOT );
40494119 }
40504120
40514121 /** @var array<Document> $collectionAttributes */
@@ -4100,6 +4170,7 @@ public function createIndex(string $collection, string $id, string $type, array
41004170 $ this ->adapter ->getSupportForAttributes (),
41014171 $ this ->adapter ->getSupportForMultipleFulltextIndexes (),
41024172 $ this ->adapter ->getSupportForIdenticalIndexes (),
4173+ $ this ->adapter ->getSupportForObject (),
41034174 );
41044175 if (!$ validator ->isValid ($ index )) {
41054176 throw new IndexException ($ validator ->getDescription ());
0 commit comments