2222use MongoDB \Exception \Exception ;
2323use MongoDB \Exception \RuntimeException ;
2424use Traversable ;
25+ use TypeError ;
2526
2627use function array_column ;
2728use function array_filter ;
3233use function assert ;
3334use function call_user_func ;
3435use function class_uses_recursive ;
36+ use function get_debug_type ;
3537use function hrtime ;
3638use function in_array ;
39+ use function is_array ;
40+ use function is_int ;
3741use function is_iterable ;
42+ use function is_string ;
3843use function iterator_to_array ;
3944use function preg_quote ;
4045use function sleep ;
@@ -84,7 +89,7 @@ public function update($models)
8489 return ;
8590 }
8691
87- $ collection = $ this ->getCollection ($ models );
92+ $ collection = $ this ->getIndexableCollection ($ models );
8893
8994 if ($ this ->softDelete && $ this ->usesSoftDelete ($ models )) {
9095 $ models ->each ->pushSoftDeleteMetadata ();
@@ -102,8 +107,8 @@ public function update($models)
102107 'updateOne ' => [
103108 ['_id ' => $ model ->getScoutKey ()],
104109 [
105- '$set ' => array_merge ($ searchableData , $ model ->scoutMetadata ()),
106110 '$setOnInsert ' => ['_id ' => $ model ->getScoutKey ()],
111+ '$set ' => array_merge ($ searchableData , $ model ->scoutMetadata ()),
107112 ],
108113 ['upsert ' => true ],
109114 ],
@@ -123,15 +128,15 @@ public function update($models)
123128 */
124129 public function delete ($ models ): void
125130 {
131+ assert ($ models instanceof Collection, new TypeError (sprintf ('Argument #1 ($models) must be of type %s, %s given ' , Collection::class, get_debug_type ($ models ))));
132+
126133 if ($ models ->isEmpty ()) {
127134 return ;
128135 }
129136
130- $ collection = $ this ->mongodb ->getCollection ($ models );
131- $ ids = array_map (fn (Model $ model ) => $ model ->getScoutKey (), $ models ->toArray ());
132- $ collection ->deleteMany ([
133- '_id ' => ['$in ' => $ ids ],
134- ]);
137+ $ collection = $ this ->getIndexableCollection ($ models );
138+ $ ids = $ models ->map (fn (Model $ model ) => $ model ->getScoutKey ())->all ();
139+ $ collection ->deleteMany (['_id ' => ['$in ' => $ ids ]]);
135140 }
136141
137142 /**
@@ -157,6 +162,9 @@ public function search(Builder $builder)
157162 */
158163 public function paginate (Builder $ builder , $ perPage , $ page )
159164 {
165+ assert (is_int ($ perPage ), new TypeError (sprintf ('Argument #2 ($perPage) must be of type int, %s given ' , get_debug_type ($ perPage ))));
166+ assert (is_int ($ page ), new TypeError (sprintf ('Argument #3 ($page) must be of type int, %s given ' , get_debug_type ($ page ))));
167+
160168 return $ this ->performSearch ($ builder , array_filter ([
161169 'filters ' => $ this ->filters ($ builder ),
162170 'limit ' => (int ) $ perPage ,
@@ -169,7 +177,7 @@ public function paginate(Builder $builder, $perPage, $page)
169177 */
170178 protected function performSearch (Builder $ builder , array $ searchParams = []): array
171179 {
172- $ collection = $ this ->getCollection ($ builder ->model );
180+ $ collection = $ this ->getSearchableCollection ($ builder ->model );
173181
174182 if ($ builder ->callback ) {
175183 $ result = call_user_func (
@@ -242,6 +250,8 @@ protected function filters(Builder $builder): array
242250 */
243251 public function mapIds ($ results ): Collection
244252 {
253+ assert (is_array ($ results ), new TypeError (sprintf ('Argument #1 ($results) must be of type array, %s given ' , get_debug_type ($ results ))));
254+
245255 return new Collection (array_column ($ results , '_id ' ));
246256 }
247257
@@ -253,6 +263,9 @@ public function mapIds($results): Collection
253263 */
254264 public function map (Builder $ builder , $ results , $ model ): Collection
255265 {
266+ assert (is_array ($ results ), new TypeError (sprintf ('Argument #2 ($results) must be of type array, %s given ' , get_debug_type ($ results ))));
267+ assert ($ model instanceof Model, new TypeError (sprintf ('Argument #3 ($model) must be of type %s, %s given ' , Model::class, get_debug_type ($ model ))));
268+
256269 if (! $ results ) {
257270 return $ model ->newCollection ();
258271 }
@@ -287,22 +300,27 @@ public function getTotalCount($results): int
287300 */
288301 public function flush ($ model ): void
289302 {
290- $ collection = $ this ->getCollection ($ model );
303+ assert ($ model instanceof Model, new TypeError (sprintf ('Argument #1 ($model) must be of type %s, %s given ' , Model::class, get_debug_type ($ model ))));
304+
305+ $ collection = $ this ->getIndexableCollection ($ model );
291306
292307 $ collection ->deleteMany ([]);
293308 }
294309
295310 /**
296311 * Map the given results to instances of the given model via a lazy collection.
297312 *
298- * @param Builder $builder
299- * @param mixed $results
300- * @param Model $model
313+ * @param Builder $builder
314+ * @param array|Cursor $results
315+ * @param Model $model
301316 *
302317 * @return LazyCollection
303318 */
304- public function lazyMap (Builder $ builder , $ results , $ model )
319+ public function lazyMap (Builder $ builder , $ results , $ model ): LazyCollection
305320 {
321+ assert ($ results instanceof Cursor || is_array ($ results ), new TypeError (sprintf ('Argument #2 ($results) must be of type %s|array, %s given ' , Cursor::class, get_debug_type ($ results ))));
322+ assert ($ model instanceof Model, new TypeError (sprintf ('Argument #3 ($model) must be of type %s, %s given ' , Model::class, get_debug_type ($ model ))));
323+
306324 if (! $ results ) {
307325 return LazyCollection::make ($ model ->newCollection ());
308326 }
@@ -341,6 +359,8 @@ public function lazyMap(Builder $builder, $results, $model)
341359 */
342360 public function createIndex ($ name , array $ options = []): void
343361 {
362+ assert (is_string ($ name ), new TypeError (sprintf ('Argument #1 ($name) must be of type string, %s given ' , get_debug_type ($ name ))));
363+
344364 $ this ->performSearchIndexOperation (function () use ($ name , $ options ) {
345365 $ this ->mongodb ->createCollection ($ name );
346366 $ collection = $ this ->mongodb ->selectCollection ($ name );
@@ -375,6 +395,8 @@ public function createIndex($name, array $options = []): void
375395 */
376396 public function deleteIndex ($ name ): void
377397 {
398+ assert (is_string ($ name ), new TypeError (sprintf ('Argument #1 ($name) must be of type string, %s given ' , get_debug_type ($ name ))));
399+
378400 $ this ->mongodb ->selectCollection ($ name )->drop ();
379401 }
380402
@@ -394,8 +416,8 @@ public function deleteAllIndexes()
394416 }
395417 }
396418
397- /** Get the MongoDB collection used as search index for the provided model */
398- private function getCollection (Model |EloquentCollection $ model ): MongoDBCollection
419+ /** Get the MongoDB collection used to search for the provided model */
420+ private function getSearchableCollection (Model |EloquentCollection $ model ): MongoDBCollection
399421 {
400422 if ($ model instanceof EloquentCollection) {
401423 $ model = $ model ->first ();
@@ -406,6 +428,18 @@ private function getCollection(Model|EloquentCollection $model): MongoDBCollecti
406428 return $ this ->mongodb ->selectCollection ($ model ->searchableAs ());
407429 }
408430
431+ /** Get the MongoDB collection used to index the provided model */
432+ private function getIndexableCollection (Model |EloquentCollection $ model ): MongoDBCollection
433+ {
434+ if ($ model instanceof EloquentCollection) {
435+ $ model = $ model ->first ();
436+ }
437+
438+ assert (in_array (Searchable::class, class_uses_recursive ($ model )), sprintf ('Model "%s" must use "%s" trait ' , $ model ::class, Searchable::class));
439+
440+ return $ this ->mongodb ->selectCollection ($ model ->indexableAs ());
441+ }
442+
409443 private static function serialize (mixed $ value ): mixed
410444 {
411445 if ($ value instanceof DateTimeInterface) {
0 commit comments