All Downloads are FREE. Search and download functionalities are using the official Maven repository.

commonMain.FilteredCollection.kt Maven / Gradle / Ivy

There is a newer version: 0.5.0
Show newest version
/*
 * Copyright (c) 2024, OpenSavvy and contributors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package opensavvy.ktmongo.sync

import opensavvy.ktmongo.bson.BsonContext
import opensavvy.ktmongo.dsl.LowLevelApi
import opensavvy.ktmongo.dsl.expr.FilterExpression
import opensavvy.ktmongo.dsl.expr.FilterOperators
import opensavvy.ktmongo.dsl.expr.UpdateOperators
import opensavvy.ktmongo.dsl.expr.UpsertOperators
import opensavvy.ktmongo.dsl.expr.common.toBsonDocument
import opensavvy.ktmongo.dsl.models.BulkWrite
import opensavvy.ktmongo.dsl.options.*

private class FilteredCollection(
	private val upstream: MongoCollection,
	private val globalFilter: FilterOperators.() -> Unit,
) : MongoCollection {

	override fun find(): MongoIterable =
		upstream.find(filter = globalFilter)

	override fun find(
		options: FindOptions.() -> Unit,
		filter: FilterOperators.() -> Unit,
	): MongoIterable =
		upstream.find(options) {
			globalFilter()
			filter()
		}

	@LowLevelApi
	override val context: BsonContext
		get() = upstream.context

	override fun count(): Long =
		upstream.count(predicate = globalFilter)

	override fun count(
		options: CountOptions.() -> Unit,
		predicate: FilterOperators.() -> Unit,
	): Long =
		upstream.count(
			options = options,
			predicate = {
				globalFilter()
				predicate()
			}
		)

	override fun countEstimated(): Long =
		count()

	override fun updateMany(
		options: UpdateOptions.() -> Unit,
		filter: FilterOperators.() -> Unit,
		update: UpdateOperators.() -> Unit,
	) {
		upstream.updateMany(
			options = options,
			filter = {
				globalFilter()
				filter()
			},
			update = update,
		)
	}

	override fun updateOne(
		options: UpdateOptions.() -> Unit,
		filter: FilterOperators.() -> Unit,
		update: UpdateOperators.() -> Unit,
	) {
		upstream.updateOne(
			options = options,
			filter = {
				globalFilter()
				filter()
			},
			update = update,
		)
	}

	override fun upsertOne(
		options: UpdateOptions.() -> Unit,
		filter: FilterOperators.() -> Unit,
		update: UpsertOperators.() -> Unit,
	) {
		upstream.upsertOne(
			options = options,
			filter = {
				globalFilter()
				filter()
			},
			update = update,
		)
	}

	override fun findOneAndUpdate(
		options: UpdateOptions.() -> Unit,
		filter: FilterOperators.() -> Unit,
		update: UpdateOperators.() -> Unit,
	): Document? =
		upstream.findOneAndUpdate(
			options = options,
			filter = {
				globalFilter()
				filter()
			},
			update = update,
		)

	override fun bulkWrite(
		options: BulkWriteOptions.() -> Unit,
		filter: FilterOperators.() -> Unit,
		operations: BulkWrite.() -> Unit
	) = upstream.bulkWrite(
		options = options,
		filter = {
			globalFilter()
			filter()
		},
		operations = operations,
	)

	override fun deleteOne(options: DeleteOneOptions.() -> Unit, filter: FilterOperators.() -> Unit) {
		upstream.deleteOne(
			options = options,
			filter = {
				globalFilter()
				filter()
			}
		)
	}

	override fun deleteMany(options: DeleteManyOptions.() -> Unit, filter: FilterOperators.() -> Unit) {
		upstream.deleteMany(
			options = options,
			filter = {
				globalFilter()
				filter()
			}
		)
	}

	override fun drop(options: DropOptions.() -> Unit) {
		deleteMany(
			options = {
			},
			filter = {
				globalFilter()
			}
		)
	}

	override fun insertOne(document: Document, options: InsertOneOptions.() -> Unit) =
		upstream.insertOne(document, options)

	override fun insertMany(documents: Iterable, options: InsertManyOptions.() -> Unit) =
		upstream.insertMany(documents, options)

	@OptIn(LowLevelApi::class)
	override fun toString(): String {
		val filter = FilterExpression(context)
			.apply(globalFilter)
			.toBsonDocument()

		return "$upstream.filter $filter"
	}
}

/**
 * Returns a filtered collection that only contains the elements that match [filter].
 *
 * This function creates a logical view of the collection: by itself, this function does nothing, and MongoDB is never
 * aware of the existence of this logical view. However, operations invoked on the returned collection will only affect
 * elements from the original that match the [filter].
 *
 * Unlike actual MongoDB views, which are read-only, collections returned by this function can also be used for write operations.
 *
 * ### Example
 *
 * A typical usage of this function is to reuse filters for multiple operations.
 * For example, if you have a concept of logical deletion, this function can be used to hide deleted values.
 *
 * ```kotlin
 * class Order(
 *     val id: String,
 *     val date: Instant,
 *     val deleted: Boolean,
 * )
 *
 * val allOrders = database.getCollection("orders").asKtMongo()
 * val activeOrders = allOrders.filter { Order::deleted ne true }
 *
 * allOrders.find()    // Returns all orders, deleted or not
 * activeOrders.find() // Only returns orders that are not logically deleted
 * ```
 */
fun  MongoCollection.filter(filter: FilterOperators.() -> Unit): MongoCollection =
	FilteredCollection(this, filter)




© 2015 - 2024 Weber Informatics LLC | Privacy Policy