From 9a21966253145c1b52fcfdb099f6ae4c7e96adb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?= Date: Sat, 2 May 2026 21:20:35 +0200 Subject: [PATCH] refactor(dsl): Operators take advantage of the KType instance --- .../operators/ArrayValueOperators.kt | 6 +- .../aggregation/operators/ValueOperators.kt | 5 +- .../commonMain/kotlin/command/BulkWrite.kt | 23 +++-- .../src/commonMain/kotlin/command/Insert.kt | 19 +++- .../src/commonMain/kotlin/command/Replace.kt | 19 +++- .../commonMain/kotlin/query/FilterQuery.kt | 5 +- .../kotlin/query/FilterQueryImpl.kt | 5 +- .../kotlin/query/FilterQueryPredicateImpl.kt | 40 ++++---- .../kotlin/query/UpdateQueryImpl.kt | 52 +++++----- .../operators/ArrayValueOperators.kt | 96 +++++++++---------- .../aggregation/operators/ValueOperators.kt | 5 +- .../commonMain/kotlin/command/BulkWrite.kt | 23 +++-- dsl/src/commonMain/kotlin/command/Insert.kt | 19 +++- dsl/src/commonMain/kotlin/command/Replace.kt | 19 +++- .../commonMain/kotlin/query/FilterQuery.kt | 5 +- .../kotlin/query/FilterQueryImpl.kt | 5 +- .../kotlin/query/FilterQueryPredicateImpl.kt | 40 ++++---- .../kotlin/query/UpdateQueryImpl.kt | 52 +++++----- .../kotlin/command/BulkWriteTest.kt | 5 +- .../commonTest/kotlin/command/InsertTest.kt | 7 +- 20 files changed, 274 insertions(+), 176 deletions(-) diff --git a/dsl-template/src/commonMain/kotlin/aggregation/operators/ArrayValueOperators.kt b/dsl-template/src/commonMain/kotlin/aggregation/operators/ArrayValueOperators.kt index 2d7fa484..7f7e7bd8 100644 --- a/dsl-template/src/commonMain/kotlin/aggregation/operators/ArrayValueOperators.kt +++ b/dsl-template/src/commonMain/kotlin/aggregation/operators/ArrayValueOperators.kt @@ -208,7 +208,7 @@ interface ArrayValueOperators : ValueOperators { @Suppress("INVISIBLE_REFERENCE") @KtMongoDsl fun Value>.filter( - limit: Value? = null, + limit: Value? = null, variableName: String = "this", predicate: AggregationOperators.(Value) -> Value, ): Value> = @@ -295,7 +295,7 @@ interface ArrayValueOperators : ValueOperators { @OptIn(LowLevelApi::class) @KtMongoDsl fun Value>.take( - limit: Value, + limit: Value, ): Value> = TakeValueOperator( input = this, @@ -354,7 +354,7 @@ interface ArrayValueOperators : ValueOperators { @OptIn(LowLevelApi::class) @KtMongoDsl fun Value>.takeLast( - limit: Value, + limit: Value, ): Value> = TakeLastValueOperator( input = this, diff --git a/dsl-template/src/commonMain/kotlin/aggregation/operators/ValueOperators.kt b/dsl-template/src/commonMain/kotlin/aggregation/operators/ValueOperators.kt index 31b77a44..a64222a6 100644 --- a/dsl-template/src/commonMain/kotlin/aggregation/operators/ValueOperators.kt +++ b/dsl-template/src/commonMain/kotlin/aggregation/operators/ValueOperators.kt @@ -102,7 +102,7 @@ interface ValueOperators : FieldDsl { */ @OptIn(LowLevelApi::class) fun of(value: Result, type: KType): Value = - LiteralValue(value, context) + LiteralValue(value, context, type) /** * Refers to a Kotlin [value] within an [aggregation value][AggregationOperators]. @@ -222,12 +222,13 @@ private class FieldValue( private class LiteralValue( val value: Any?, context: BsonContext, + val type: KType, ) : AbstractValue(context) { @LowLevelApi override fun write(writer: BsonValueWriter) { writer.writeDocument { - writeObjectSafe("\$literal", value) + writeSafe("\$literal", value, type) } } } diff --git a/dsl-template/src/commonMain/kotlin/command/BulkWrite.kt b/dsl-template/src/commonMain/kotlin/command/BulkWrite.kt index 90569f1d..274b0ebf 100644 --- a/dsl-template/src/commonMain/kotlin/command/BulkWrite.kt +++ b/dsl-template/src/commonMain/kotlin/command/BulkWrite.kt @@ -31,6 +31,7 @@ import opensavvy.ktmongo.dsl.tree.AbstractBsonNode import opensavvy.ktmongo.dsl.tree.CompoundNode import opensavvy.ktmongo.dsl.tree.Node import opensavvy.ktmongo.dsl.tree.acceptAll +import kotlin.reflect.KType sealed interface AvailableInBulkWrite : Node, Command @@ -88,12 +89,17 @@ class BulkWrite private constructor( context: BsonContext, private val globalFilter: FilterQuery.() -> Unit, val options: BulkWriteOptions, + val documentType: KType, ) : Command, AbstractBsonNode(context), CompoundNode> { private val _operations = ArrayList>() val operations: Sequence> get() = _operations.asSequence() - constructor(context: BsonContext, globalFilter: FilterQuery.() -> Unit) : this(context, globalFilter, BulkWriteOptions(context)) + constructor( + context: BsonContext, + documentType: KType, + globalFilter: FilterQuery.() -> Unit, + ) : this(context, globalFilter, BulkWriteOptions(context), documentType) @LowLevelApi @DangerousMongoApi @@ -126,10 +132,11 @@ class BulkWrite private constructor( val child = BulkWrite( context = context, + documentType, globalFilter = { parent.globalFilter(this) filter() - } + }, ) child.operations() @@ -167,7 +174,7 @@ class BulkWrite private constructor( document: Document, options: InsertOneOptions.() -> Unit = {}, ) { - val model = InsertOne(context, document) + val model = InsertOne(context, document, documentType) model.options.options() @@ -412,7 +419,7 @@ class BulkWrite private constructor( filter: FilterQuery.() -> Unit = {}, document: Document, ) { - val model = ReplaceOne(context, document) + val model = ReplaceOne(context, document, documentType) model.options.options() model.filter.globalFilter() @@ -461,7 +468,7 @@ class BulkWrite private constructor( filter: FilterQuery.() -> Unit = {}, document: Document, ) { - val model = RepsertOne(context, document) + val model = RepsertOne(context, document, documentType) model.options.options() model.filter.globalFilter() @@ -479,7 +486,7 @@ class BulkWrite private constructor( when (operation) { is InsertOne<*> -> { writeInt32("insert", 0) - writeObjectSafe("document", operation.document) + writeSafe("document", operation.document) operation.options.writeTo(this) } @@ -500,7 +507,7 @@ class BulkWrite private constructor( writeDocument("filter") { operation.filter.writeTo(this) } - writeObjectSafe("updateMods", operation.document) + writeSafe("updateMods", operation.document) writeBoolean("multi", false) operation.options.writeTo(this) } @@ -510,7 +517,7 @@ class BulkWrite private constructor( writeDocument("filter") { operation.filter.writeTo(this) } - writeObjectSafe("updateMods", operation.document) + writeSafe("updateMods", operation.document) writeBoolean("multi", false) writeBoolean("upsert", true) operation.options.writeTo(this) diff --git a/dsl-template/src/commonMain/kotlin/command/Insert.kt b/dsl-template/src/commonMain/kotlin/command/Insert.kt index 8791fd90..9c9f5fa4 100644 --- a/dsl-template/src/commonMain/kotlin/command/Insert.kt +++ b/dsl-template/src/commonMain/kotlin/command/Insert.kt @@ -24,6 +24,7 @@ import opensavvy.ktmongo.dsl.options.Options import opensavvy.ktmongo.dsl.options.OptionsHolder import opensavvy.ktmongo.dsl.options.WithWriteConcern import opensavvy.ktmongo.dsl.tree.AbstractBsonNode +import kotlin.reflect.KType /** * Inserting a single element in a collection. @@ -46,14 +47,19 @@ class InsertOne private constructor( context: BsonContext, val options: InsertOneOptions, val document: Document, + val documentType: KType, ) : Command, AbstractBsonNode(context), AvailableInBulkWrite { - constructor(context: BsonContext, document: Document) : this(context, InsertOneOptions(context), document) + constructor( + context: BsonContext, + document: Document, + documentType: KType, + ) : this(context, InsertOneOptions(context), document, documentType) @LowLevelApi override fun write(writer: BsonFieldWriter) = with(writer) { writeArray("documents") { - writeObjectSafe(document) + writeSafe(document, documentType) } options.writeTo(this) @@ -81,15 +87,20 @@ class InsertMany private constructor( context: BsonContext, val options: InsertManyOptions, val documents: List, + val documentType: KType, ) : Command, AbstractBsonNode(context) { - constructor(context: BsonContext, documents: List) : this(context, InsertManyOptions(context), documents) + constructor( + context: BsonContext, + documents: List, + documentType: KType, + ) : this(context, InsertManyOptions(context), documents, documentType) @LowLevelApi override fun write(writer: BsonFieldWriter) = with(writer) { writeArray("documents") { for (document in documents) { - writeObjectSafe(document) + writeSafe(document, documentType) } } diff --git a/dsl-template/src/commonMain/kotlin/command/Replace.kt b/dsl-template/src/commonMain/kotlin/command/Replace.kt index ab7e521c..c780bfc9 100644 --- a/dsl-template/src/commonMain/kotlin/command/Replace.kt +++ b/dsl-template/src/commonMain/kotlin/command/Replace.kt @@ -25,6 +25,7 @@ import opensavvy.ktmongo.dsl.options.OptionsHolder import opensavvy.ktmongo.dsl.options.WithWriteConcern import opensavvy.ktmongo.dsl.query.FilterQuery import opensavvy.ktmongo.dsl.tree.AbstractBsonNode +import kotlin.reflect.KType /** * Replaces a single element in a collection. @@ -47,10 +48,15 @@ class ReplaceOne private constructor( val options: ReplaceOptions, val filter: FilterQuery, val document: Document, + val documentType: KType, ) : AbstractBsonNode(context), Command, AvailableInBulkWrite { @OptIn(LowLevelApi::class) - constructor(context: BsonContext, document: Document) : this(context, ReplaceOptions(context), FilterQuery(context), document) + constructor( + context: BsonContext, + document: Document, + documentType: KType, + ) : this(context, ReplaceOptions(context), FilterQuery(context), document, documentType) @LowLevelApi override fun write(writer: BsonFieldWriter) = with(writer) { @@ -59,7 +65,7 @@ class ReplaceOne private constructor( writeDocument("q") { filter.writeTo(this) } - writeObjectSafe("u", document) + writeSafe("u", document, documentType) writeBoolean("upsert", false) writeBoolean("multi", false) } @@ -90,10 +96,15 @@ class RepsertOne private constructor( val options: ReplaceOptions, val filter: FilterQuery, val document: Document, + val documentType: KType, ) : AbstractBsonNode(context), Command, AvailableInBulkWrite { @OptIn(LowLevelApi::class) - constructor(context: BsonContext, document: Document) : this(context, ReplaceOptions(context), FilterQuery(context), document) + constructor( + context: BsonContext, + document: Document, + documentType: KType, + ) : this(context, ReplaceOptions(context), FilterQuery(context), document, documentType) @LowLevelApi override fun write(writer: BsonFieldWriter) = with(writer) { @@ -102,7 +113,7 @@ class RepsertOne private constructor( writeDocument("q") { filter.writeTo(this) } - writeObjectSafe("u", document) + writeSafe("u", document, documentType) writeBoolean("upsert", true) writeBoolean("multi", false) } diff --git a/dsl-template/src/commonMain/kotlin/query/FilterQuery.kt b/dsl-template/src/commonMain/kotlin/query/FilterQuery.kt index 93e18117..894e736b 100644 --- a/dsl-template/src/commonMain/kotlin/query/FilterQuery.kt +++ b/dsl-template/src/commonMain/kotlin/query/FilterQuery.kt @@ -16,6 +16,7 @@ package opensavvy.ktmongo.dsl.query +import opensavvy.ktmongo.bson.BsonDocument import opensavvy.ktmongo.bson.BsonType import opensavvy.ktmongo.bson.DEPRECATED_IN_BSON_SPEC import opensavvy.ktmongo.dsl.DangerousMongoApi @@ -665,7 +666,7 @@ interface FilterQuery : CompoundBsonNode, FieldDsl { fun Field>.isMapEmpty() { or { doesNotExist() - FieldImpl(path) eq context.buildDocument { } + FieldImpl(path).eq(context.buildDocument { }, typeOf()) } } @@ -724,7 +725,7 @@ interface FilterQuery : CompoundBsonNode, FieldDsl { @OptIn(LowLevelApi::class) @KtMongoDsl fun Field>.isMapNotEmpty() { - FieldImpl(path) gt context.buildDocument { } + FieldImpl(path).gt(context.buildDocument { }, typeOf()) } // endregion diff --git a/dsl-template/src/commonMain/kotlin/query/FilterQueryImpl.kt b/dsl-template/src/commonMain/kotlin/query/FilterQueryImpl.kt index 123a6f04..9372ef50 100644 --- a/dsl-template/src/commonMain/kotlin/query/FilterQueryImpl.kt +++ b/dsl-template/src/commonMain/kotlin/query/FilterQueryImpl.kt @@ -240,7 +240,7 @@ private class FilterQueryImpl( @OptIn(LowLevelApi::class, DangerousMongoApi::class) @KtMongoDsl override fun Field>.containsAll(values: Collection, type: KType) { - accept(ArrayAllBsonNodeNode(path, values, context)) + accept(ArrayAllBsonNodeNode(path, values, context, type)) } @LowLevelApi @@ -248,13 +248,14 @@ private class FilterQueryImpl( val path: Path, val values: Collection, context: BsonContext, + val type: KType, ) : FilterBsonNodeNode(context) { override fun write(writer: BsonFieldWriter) = with(writer) { writeDocument(path.toString()) { writeArray("\$all") { for (value in values) { - writeObjectSafe(value) + writeSafe(value, type) } } } diff --git a/dsl-template/src/commonMain/kotlin/query/FilterQueryPredicateImpl.kt b/dsl-template/src/commonMain/kotlin/query/FilterQueryPredicateImpl.kt index a941cf01..f5a69e6a 100644 --- a/dsl-template/src/commonMain/kotlin/query/FilterQueryPredicateImpl.kt +++ b/dsl-template/src/commonMain/kotlin/query/FilterQueryPredicateImpl.kt @@ -56,17 +56,18 @@ private class FilterQueryPredicateImpl( @OptIn(LowLevelApi::class, DangerousMongoApi::class) @KtMongoDsl override fun eq(value: T) { - accept(EqualityBsonNodeNode(value, context)) + accept(EqualityBsonNodeNode(value, context, type)) } @LowLevelApi private class EqualityBsonNodeNode( val value: T, context: BsonContext, + val type: KType, ) : PredicateBsonNodeNode(context) { override fun write(writer: BsonFieldWriter) { - writer.writeObjectSafe("\$eq", value) + writer.writeSafe("\$eq", value, type) } } @@ -76,17 +77,18 @@ private class FilterQueryPredicateImpl( @OptIn(LowLevelApi::class, DangerousMongoApi::class) @KtMongoDsl override fun ne(value: T) { - accept(InequalityBsonNodeNode(value, context)) + accept(InequalityBsonNodeNode(value, context, type)) } @LowLevelApi private class InequalityBsonNodeNode( val value: T, context: BsonContext, + val type: KType, ) : PredicateBsonNodeNode(context) { override fun write(writer: BsonFieldWriter) { - writer.writeObjectSafe("\$ne", value) + writer.writeSafe("\$ne", value, type) } } @@ -171,72 +173,76 @@ private class FilterQueryPredicateImpl( @OptIn(LowLevelApi::class, DangerousMongoApi::class) @KtMongoDsl override fun gt(value: T) { - accept(GtPredicateBsonNodeNode(value, context)) + accept(GtPredicateBsonNodeNode(value, context, type)) } @LowLevelApi private class GtPredicateBsonNodeNode( private val value: T, context: BsonContext, + val type: KType, ) : PredicateBsonNodeNode(context) { @LowLevelApi override fun write(writer: BsonFieldWriter) { - writer.writeObjectSafe("\$gt", value) + writer.writeSafe("\$gt", value, type) } } @OptIn(LowLevelApi::class, DangerousMongoApi::class) @KtMongoDsl override fun gte(value: T) { - accept(GtePredicateBsonNodeNode(value, context)) + accept(GtePredicateBsonNodeNode(value, context, type)) } @LowLevelApi private class GtePredicateBsonNodeNode( private val value: T, context: BsonContext, + val type: KType, ) : PredicateBsonNodeNode(context) { @LowLevelApi override fun write(writer: BsonFieldWriter) { - writer.writeObjectSafe("\$gte", value) + writer.writeSafe("\$gte", value, type) } } @OptIn(LowLevelApi::class, DangerousMongoApi::class) @KtMongoDsl override fun lt(value: T) { - accept(LtPredicateBsonNodeNode(value, context)) + accept(LtPredicateBsonNodeNode(value, context, type)) } @LowLevelApi private class LtPredicateBsonNodeNode( private val value: T, context: BsonContext, + val type: KType, ) : PredicateBsonNodeNode(context) { @LowLevelApi override fun write(writer: BsonFieldWriter) { - writer.writeObjectSafe("\$lt", value) + writer.writeSafe("\$lt", value, type) } } @OptIn(LowLevelApi::class, DangerousMongoApi::class) @KtMongoDsl override fun lte(value: T) { - accept(LtePredicateBsonNodeNode(value, context)) + accept(LtePredicateBsonNodeNode(value, context, type)) } @LowLevelApi private class LtePredicateBsonNodeNode( private val value: T, context: BsonContext, + val type: KType, ) : PredicateBsonNodeNode(context) { @LowLevelApi override fun write(writer: BsonFieldWriter) { - writer.writeObjectSafe("\$lte", value) + writer.writeSafe("\$lte", value, type) } } @@ -246,20 +252,21 @@ private class FilterQueryPredicateImpl( @OptIn(LowLevelApi::class, DangerousMongoApi::class) @KtMongoDsl override fun isOneOf(values: Collection) { - accept(OneOfPredicateBsonNodeNode(values, context)) + accept(OneOfPredicateBsonNodeNode(values, context, type)) } @LowLevelApi private class OneOfPredicateBsonNodeNode( val values: Collection, context: BsonContext, + val type: KType, ) : PredicateBsonNodeNode(context) { @LowLevelApi override fun write(writer: BsonFieldWriter) { writer.writeArray("\$in") { for (value in values) - writeObjectSafe(value) + writeSafe(value, type) } } } @@ -270,20 +277,21 @@ private class FilterQueryPredicateImpl( @OptIn(LowLevelApi::class, DangerousMongoApi::class) @KtMongoDsl override fun isNotOneOf(values: Collection) { - accept(NotOneOfPredicateExpressionNode(values, context)) + accept(NotOneOfPredicateExpressionNode(values, context, type)) } @LowLevelApi private class NotOneOfPredicateExpressionNode( val values: Collection, context: BsonContext, + val type: KType, ) : PredicateBsonNodeNode(context) { @LowLevelApi override fun write(writer: BsonFieldWriter) { writer.writeArray("\$nin") { for (value in values) - writeObjectSafe(value) + writeSafe(value, type) } } } diff --git a/dsl-template/src/commonMain/kotlin/query/UpdateQueryImpl.kt b/dsl-template/src/commonMain/kotlin/query/UpdateQueryImpl.kt index c6d4e0c9..7a4a783f 100644 --- a/dsl-template/src/commonMain/kotlin/query/UpdateQueryImpl.kt +++ b/dsl-template/src/commonMain/kotlin/query/UpdateQueryImpl.kt @@ -84,6 +84,14 @@ private class UpdateQueryImpl( return this } + private class Value( + val value: Any?, + val type: KType, + ) { + override fun toString(): String = + "Value($value, $type)" + } + @LowLevelApi private sealed class UpdateBsonNodeNode(context: BsonContext) : AbstractBsonNode(context) @@ -94,12 +102,12 @@ private class UpdateQueryImpl( @Suppress("INVISIBLE_REFERENCE") @KtMongoDsl override fun <@kotlin.internal.OnlyInputTypes V> Field.set(value: V, type: KType) { - accept(SetBsonNodeNode(listOf(this.path to value), context)) + accept(SetBsonNodeNode(listOf(this.path to Value(value, type)), context)) } @LowLevelApi private class SetBsonNodeNode( - val mappings: List>, + val mappings: List>, context: BsonContext, ) : UpdateBsonNodeNode(context) { @@ -109,7 +117,7 @@ private class UpdateQueryImpl( override fun write(writer: BsonFieldWriter) = with(writer) { writeDocument("\$set") { for ((field, value) in mappings) { - writeObjectSafe(field.toString(), value) + writeSafe(field.toString(), value.value, value.type) } } } @@ -122,12 +130,12 @@ private class UpdateQueryImpl( @Suppress("INVISIBLE_REFERENCE") @KtMongoDsl override fun <@kotlin.internal.OnlyInputTypes V> Field.setOnInsert(value: V, type: KType) { - accept(SetOnInsertBsonNodeNode(listOf(this.path to value), context)) + accept(SetOnInsertBsonNodeNode(listOf(this.path to Value(value, type)), context)) } @LowLevelApi private class SetOnInsertBsonNodeNode( - val mappings: List>, + val mappings: List>, context: BsonContext, ) : UpdateBsonNodeNode(context) { override fun simplify(): AbstractBsonNode? = @@ -136,7 +144,7 @@ private class UpdateQueryImpl( override fun write(writer: BsonFieldWriter) = with(writer) { writeDocument("\$setOnInsert") { for ((field, value) in mappings) { - writeObjectSafe(field.toString(), value) + writeSafe(field.toString(), value.value, value.type) } } } @@ -149,12 +157,12 @@ private class UpdateQueryImpl( @Suppress("INVISIBLE_REFERENCE") @KtMongoDsl override fun <@kotlin.internal.OnlyInputTypes V : Number> Field.inc(amount: V, type: KType) { - accept(IncrementBsonNodeNode(listOf(this.path to amount), context)) + accept(IncrementBsonNodeNode(listOf(this.path to Value(amount, type)), context)) } @LowLevelApi private class IncrementBsonNodeNode( - val mappings: List>, + val mappings: List>, context: BsonContext, ) : UpdateBsonNodeNode(context) { override fun simplify(): AbstractBsonNode? = @@ -163,7 +171,7 @@ private class UpdateQueryImpl( override fun write(writer: BsonFieldWriter) = with(writer) { writeDocument("\$inc") { for ((field, value) in mappings) { - writeObjectSafe(field.toString(), value) + writeSafe(field.toString(), value.value, value.type) } } } @@ -176,12 +184,12 @@ private class UpdateQueryImpl( @Suppress("INVISIBLE_REFERENCE") @KtMongoDsl override fun <@kotlin.internal.OnlyInputTypes V : Number> Field.mul(amount: V, type: KType) { - accept(MultiplyBsonNodeNode(listOf(this.path to amount), context)) + accept(MultiplyBsonNodeNode(listOf(this.path to Value(amount, type)), context)) } @LowLevelApi private class MultiplyBsonNodeNode( - val mappings: List>, + val mappings: List>, context: BsonContext, ) : UpdateBsonNodeNode(context) { override fun simplify(): AbstractBsonNode? = @@ -190,7 +198,7 @@ private class UpdateQueryImpl( override fun write(writer: BsonFieldWriter) = with(writer) { writeDocument("\$mul") { for ((field, value) in mappings) { - writeObjectSafe(field.toString(), value) + writeSafe(field.toString(), value.value, value.type) } } } @@ -230,12 +238,12 @@ private class UpdateQueryImpl( @Suppress("INVISIBLE_REFERENCE") @KtMongoDsl override fun <@kotlin.internal.OnlyInputTypes V : Comparable> Field.min(value: V, type: KType) { - accept(MinBsonNodeNode(listOf(this.path to value), context)) + accept(MinBsonNodeNode(listOf(this.path to Value(value, type)), context)) } @LowLevelApi private class MinBsonNodeNode( - val mappings: List>, + val mappings: List>, context: BsonContext, ) : UpdateBsonNodeNode(context) { override fun simplify(): AbstractBsonNode? = @@ -244,7 +252,7 @@ private class UpdateQueryImpl( override fun write(writer: BsonFieldWriter) = with(writer) { writeDocument("\$min") { for ((field, value) in mappings) { - writeObjectSafe(field.toString(), value) + writeSafe(field.toString(), value.value, value.type) } } } @@ -257,12 +265,12 @@ private class UpdateQueryImpl( @Suppress("INVISIBLE_REFERENCE") @KtMongoDsl override fun <@kotlin.internal.OnlyInputTypes V : Comparable> Field.max(value: V, type: KType) { - accept(MaxBsonNodeNode(listOf(this.path to value), context)) + accept(MaxBsonNodeNode(listOf(this.path to Value(value, type)), context)) } @LowLevelApi private class MaxBsonNodeNode( - val mappings: List>, + val mappings: List>, context: BsonContext, ) : UpdateBsonNodeNode(context) { override fun simplify(): AbstractBsonNode? = @@ -271,7 +279,7 @@ private class UpdateQueryImpl( override fun write(writer: BsonFieldWriter) = with(writer) { writeDocument("\$max") { for ((field, value) in mappings) { - writeObjectSafe(field.toString(), value) + writeSafe(field.toString(), value.value, value.type) } } } @@ -350,12 +358,12 @@ private class UpdateQueryImpl( @OptIn(DangerousMongoApi::class, LowLevelApi::class) override fun Field>.addToSet(value: V, type: KType) { - accept(AddToSetBsonNode(listOf(this.path to value), context)) + accept(AddToSetBsonNode(listOf(this.path to Value(value, type)), context)) } @LowLevelApi private class AddToSetBsonNode( - val mappings: List>, + val mappings: List>, context: BsonContext, ) : UpdateBsonNodeNode(context) { @@ -371,12 +379,12 @@ private class UpdateQueryImpl( writeDocument($$"$addToSet") { for ((field, values) in groupedMappings) { if (values.size == 1) - writeObjectSafe(field.toString(), values.single()) + writeSafe(field.toString(), values.single().value, values.single().type) else writeDocument(field.toString()) { writeArray($$"$each") { for (value in values) - writeObjectSafe(value) + writeSafe(value.value, value.type) } } } diff --git a/dsl/src/commonMain/kotlin/aggregation/operators/ArrayValueOperators.kt b/dsl/src/commonMain/kotlin/aggregation/operators/ArrayValueOperators.kt index aa193299..d8110fd4 100644 --- a/dsl/src/commonMain/kotlin/aggregation/operators/ArrayValueOperators.kt +++ b/dsl/src/commonMain/kotlin/aggregation/operators/ArrayValueOperators.kt @@ -362,7 +362,7 @@ interface ArrayValueOperators : ValueOperators { @Suppress("INVISIBLE_REFERENCE") @KtMongoDsl fun Value>.filter( - limit: Value? = null, + limit: Value? = null, variableName: String = "this", predicate: AggregationOperators.(Value) -> Value, ): Value> = @@ -410,7 +410,7 @@ interface ArrayValueOperators : ValueOperators { @Suppress("INAPPLICABLE_JVM_NAME", "INVISIBLE_REFERENCE") @KtMongoDsl fun Value>.filter( - limit: opensavvy.ktmongo.dsl.path.Field, + limit: opensavvy.ktmongo.dsl.path.Field, variableName: String = "this", predicate: AggregationOperators.(Value) -> Value, ): Value> = @@ -452,7 +452,7 @@ interface ArrayValueOperators : ValueOperators { @Suppress("INAPPLICABLE_JVM_NAME", "INVISIBLE_REFERENCE") @KtMongoDsl fun Value>.filter( - limit: kotlin.reflect.KProperty1, + limit: kotlin.reflect.KProperty1, variableName: String = "this", predicate: AggregationOperators.(Value) -> Value, ): Value> = @@ -494,7 +494,7 @@ interface ArrayValueOperators : ValueOperators { @Suppress("INVISIBLE_REFERENCE") @KtMongoDsl fun Value>.filter( - limit: Number, + limit: Int, variableName: String = "this", predicate: AggregationOperators.(Value) -> Value, ): Value> = @@ -536,7 +536,7 @@ interface ArrayValueOperators : ValueOperators { @Suppress("INAPPLICABLE_JVM_NAME", "INVISIBLE_REFERENCE") @KtMongoDsl fun opensavvy.ktmongo.dsl.path.Field>.filter( - limit: Value? = null, + limit: Value? = null, variableName: String = "this", predicate: AggregationOperators.(Value) -> Value, ): Value> = @@ -578,7 +578,7 @@ interface ArrayValueOperators : ValueOperators { @Suppress("INAPPLICABLE_JVM_NAME", "INVISIBLE_REFERENCE") @KtMongoDsl fun opensavvy.ktmongo.dsl.path.Field>.filter( - limit: opensavvy.ktmongo.dsl.path.Field, + limit: opensavvy.ktmongo.dsl.path.Field, variableName: String = "this", predicate: AggregationOperators.(Value) -> Value, ): Value> = @@ -620,7 +620,7 @@ interface ArrayValueOperators : ValueOperators { @Suppress("INAPPLICABLE_JVM_NAME", "INVISIBLE_REFERENCE") @KtMongoDsl fun opensavvy.ktmongo.dsl.path.Field>.filter( - limit: kotlin.reflect.KProperty1, + limit: kotlin.reflect.KProperty1, variableName: String = "this", predicate: AggregationOperators.(Value) -> Value, ): Value> = @@ -662,7 +662,7 @@ interface ArrayValueOperators : ValueOperators { @Suppress("INAPPLICABLE_JVM_NAME", "INVISIBLE_REFERENCE") @KtMongoDsl fun opensavvy.ktmongo.dsl.path.Field>.filter( - limit: Number, + limit: Int, variableName: String = "this", predicate: AggregationOperators.(Value) -> Value, ): Value> = @@ -704,7 +704,7 @@ interface ArrayValueOperators : ValueOperators { @Suppress("INAPPLICABLE_JVM_NAME", "INVISIBLE_REFERENCE") @KtMongoDsl fun kotlin.reflect.KProperty1>.filter( - limit: Value? = null, + limit: Value? = null, variableName: String = "this", predicate: AggregationOperators.(Value) -> Value, ): Value> = @@ -746,7 +746,7 @@ interface ArrayValueOperators : ValueOperators { @Suppress("INAPPLICABLE_JVM_NAME", "INVISIBLE_REFERENCE") @KtMongoDsl fun kotlin.reflect.KProperty1>.filter( - limit: opensavvy.ktmongo.dsl.path.Field, + limit: opensavvy.ktmongo.dsl.path.Field, variableName: String = "this", predicate: AggregationOperators.(Value) -> Value, ): Value> = @@ -788,7 +788,7 @@ interface ArrayValueOperators : ValueOperators { @Suppress("INAPPLICABLE_JVM_NAME", "INVISIBLE_REFERENCE") @KtMongoDsl fun kotlin.reflect.KProperty1>.filter( - limit: kotlin.reflect.KProperty1, + limit: kotlin.reflect.KProperty1, variableName: String = "this", predicate: AggregationOperators.(Value) -> Value, ): Value> = @@ -830,7 +830,7 @@ interface ArrayValueOperators : ValueOperators { @Suppress("INAPPLICABLE_JVM_NAME", "INVISIBLE_REFERENCE") @KtMongoDsl fun kotlin.reflect.KProperty1>.filter( - limit: Number, + limit: Int, variableName: String = "this", predicate: AggregationOperators.(Value) -> Value, ): Value> = @@ -873,7 +873,7 @@ interface ArrayValueOperators : ValueOperators { @Suppress("INAPPLICABLE_JVM_NAME", "INVISIBLE_REFERENCE") @KtMongoDsl fun Collection.filter( - limit: Value? = null, + limit: Value? = null, variableName: String = "this", predicate: AggregationOperators.(Value) -> Value, ): Value> = @@ -916,7 +916,7 @@ interface ArrayValueOperators : ValueOperators { @Suppress("INAPPLICABLE_JVM_NAME", "INVISIBLE_REFERENCE") @KtMongoDsl fun Collection.filter( - limit: opensavvy.ktmongo.dsl.path.Field, + limit: opensavvy.ktmongo.dsl.path.Field, variableName: String = "this", predicate: AggregationOperators.(Value) -> Value, ): Value> = @@ -959,7 +959,7 @@ interface ArrayValueOperators : ValueOperators { @Suppress("INAPPLICABLE_JVM_NAME", "INVISIBLE_REFERENCE") @KtMongoDsl fun Collection.filter( - limit: kotlin.reflect.KProperty1, + limit: kotlin.reflect.KProperty1, variableName: String = "this", predicate: AggregationOperators.(Value) -> Value, ): Value> = @@ -1002,7 +1002,7 @@ interface ArrayValueOperators : ValueOperators { @Suppress("INAPPLICABLE_JVM_NAME", "INVISIBLE_REFERENCE") @KtMongoDsl fun Collection.filter( - limit: Number, + limit: Int, variableName: String = "this", predicate: AggregationOperators.(Value) -> Value, ): Value> = @@ -1083,7 +1083,7 @@ interface ArrayValueOperators : ValueOperators { @OptIn(LowLevelApi::class) @KtMongoDsl fun Value>.take( - limit: Value, + limit: Value, ): Value> = TakeValueOperator( input = this, @@ -1119,7 +1119,7 @@ interface ArrayValueOperators : ValueOperators { @OptIn(LowLevelApi::class) @KtMongoDsl fun Value>.take( - limit: opensavvy.ktmongo.dsl.path.Field, + limit: opensavvy.ktmongo.dsl.path.Field, ): Value> = this.take(of(limit)) @@ -1151,7 +1151,7 @@ interface ArrayValueOperators : ValueOperators { @OptIn(LowLevelApi::class) @KtMongoDsl fun Value>.take( - limit: kotlin.reflect.KProperty1, + limit: kotlin.reflect.KProperty1, ): Value> = this.take(of(limit)) @@ -1183,7 +1183,7 @@ interface ArrayValueOperators : ValueOperators { @OptIn(LowLevelApi::class) @KtMongoDsl final inline fun Value>.take( - limit: Number, + limit: Int, ): Value> = this.take(of(limit)) @@ -1215,7 +1215,7 @@ interface ArrayValueOperators : ValueOperators { @OptIn(LowLevelApi::class) @KtMongoDsl fun opensavvy.ktmongo.dsl.path.Field>.take( - limit: Value, + limit: Value, ): Value> = of(this).take(limit) @@ -1247,7 +1247,7 @@ interface ArrayValueOperators : ValueOperators { @OptIn(LowLevelApi::class) @KtMongoDsl fun opensavvy.ktmongo.dsl.path.Field>.take( - limit: opensavvy.ktmongo.dsl.path.Field, + limit: opensavvy.ktmongo.dsl.path.Field, ): Value> = of(this).take(of(limit)) @@ -1279,7 +1279,7 @@ interface ArrayValueOperators : ValueOperators { @OptIn(LowLevelApi::class) @KtMongoDsl fun opensavvy.ktmongo.dsl.path.Field>.take( - limit: kotlin.reflect.KProperty1, + limit: kotlin.reflect.KProperty1, ): Value> = of(this).take(of(limit)) @@ -1311,7 +1311,7 @@ interface ArrayValueOperators : ValueOperators { @OptIn(LowLevelApi::class) @KtMongoDsl final inline fun opensavvy.ktmongo.dsl.path.Field>.take( - limit: Number, + limit: Int, ): Value> = of(this).take(of(limit)) @@ -1343,7 +1343,7 @@ interface ArrayValueOperators : ValueOperators { @OptIn(LowLevelApi::class) @KtMongoDsl fun kotlin.reflect.KProperty1>.take( - limit: Value, + limit: Value, ): Value> = of(this).take(limit) @@ -1375,7 +1375,7 @@ interface ArrayValueOperators : ValueOperators { @OptIn(LowLevelApi::class) @KtMongoDsl fun kotlin.reflect.KProperty1>.take( - limit: opensavvy.ktmongo.dsl.path.Field, + limit: opensavvy.ktmongo.dsl.path.Field, ): Value> = of(this).take(of(limit)) @@ -1407,7 +1407,7 @@ interface ArrayValueOperators : ValueOperators { @OptIn(LowLevelApi::class) @KtMongoDsl fun kotlin.reflect.KProperty1>.take( - limit: kotlin.reflect.KProperty1, + limit: kotlin.reflect.KProperty1, ): Value> = of(this).take(of(limit)) @@ -1439,7 +1439,7 @@ interface ArrayValueOperators : ValueOperators { @OptIn(LowLevelApi::class) @KtMongoDsl final inline fun kotlin.reflect.KProperty1>.take( - limit: Number, + limit: Int, ): Value> = of(this).take(of(limit)) @@ -1472,7 +1472,7 @@ interface ArrayValueOperators : ValueOperators { @OptIn(LowLevelApi::class) @KtMongoDsl fun Collection.take( - limit: Value, + limit: Value, ): Value> = of(this).take(limit) @@ -1505,7 +1505,7 @@ interface ArrayValueOperators : ValueOperators { @OptIn(LowLevelApi::class) @KtMongoDsl fun Collection.take( - limit: opensavvy.ktmongo.dsl.path.Field, + limit: opensavvy.ktmongo.dsl.path.Field, ): Value> = of(this).take(of(limit)) @@ -1538,7 +1538,7 @@ interface ArrayValueOperators : ValueOperators { @OptIn(LowLevelApi::class) @KtMongoDsl fun Collection.take( - limit: kotlin.reflect.KProperty1, + limit: kotlin.reflect.KProperty1, ): Value> = of(this).take(of(limit)) @@ -1571,7 +1571,7 @@ interface ArrayValueOperators : ValueOperators { @OptIn(LowLevelApi::class) @KtMongoDsl final inline fun Collection.take( - limit: Number, + limit: Int, ): Value> = of(this).take(of(limit)) @@ -1626,7 +1626,7 @@ interface ArrayValueOperators : ValueOperators { @OptIn(LowLevelApi::class) @KtMongoDsl fun Value>.takeLast( - limit: Value, + limit: Value, ): Value> = TakeLastValueOperator( input = this, @@ -1662,7 +1662,7 @@ interface ArrayValueOperators : ValueOperators { @OptIn(LowLevelApi::class) @KtMongoDsl fun Value>.takeLast( - limit: opensavvy.ktmongo.dsl.path.Field, + limit: opensavvy.ktmongo.dsl.path.Field, ): Value> = this.takeLast(of(limit)) @@ -1694,7 +1694,7 @@ interface ArrayValueOperators : ValueOperators { @OptIn(LowLevelApi::class) @KtMongoDsl fun Value>.takeLast( - limit: kotlin.reflect.KProperty1, + limit: kotlin.reflect.KProperty1, ): Value> = this.takeLast(of(limit)) @@ -1726,7 +1726,7 @@ interface ArrayValueOperators : ValueOperators { @OptIn(LowLevelApi::class) @KtMongoDsl final inline fun Value>.takeLast( - limit: Number, + limit: Int, ): Value> = this.takeLast(of(limit)) @@ -1758,7 +1758,7 @@ interface ArrayValueOperators : ValueOperators { @OptIn(LowLevelApi::class) @KtMongoDsl fun opensavvy.ktmongo.dsl.path.Field>.takeLast( - limit: Value, + limit: Value, ): Value> = of(this).takeLast(limit) @@ -1790,7 +1790,7 @@ interface ArrayValueOperators : ValueOperators { @OptIn(LowLevelApi::class) @KtMongoDsl fun opensavvy.ktmongo.dsl.path.Field>.takeLast( - limit: opensavvy.ktmongo.dsl.path.Field, + limit: opensavvy.ktmongo.dsl.path.Field, ): Value> = of(this).takeLast(of(limit)) @@ -1822,7 +1822,7 @@ interface ArrayValueOperators : ValueOperators { @OptIn(LowLevelApi::class) @KtMongoDsl fun opensavvy.ktmongo.dsl.path.Field>.takeLast( - limit: kotlin.reflect.KProperty1, + limit: kotlin.reflect.KProperty1, ): Value> = of(this).takeLast(of(limit)) @@ -1854,7 +1854,7 @@ interface ArrayValueOperators : ValueOperators { @OptIn(LowLevelApi::class) @KtMongoDsl final inline fun opensavvy.ktmongo.dsl.path.Field>.takeLast( - limit: Number, + limit: Int, ): Value> = of(this).takeLast(of(limit)) @@ -1886,7 +1886,7 @@ interface ArrayValueOperators : ValueOperators { @OptIn(LowLevelApi::class) @KtMongoDsl fun kotlin.reflect.KProperty1>.takeLast( - limit: Value, + limit: Value, ): Value> = of(this).takeLast(limit) @@ -1918,7 +1918,7 @@ interface ArrayValueOperators : ValueOperators { @OptIn(LowLevelApi::class) @KtMongoDsl fun kotlin.reflect.KProperty1>.takeLast( - limit: opensavvy.ktmongo.dsl.path.Field, + limit: opensavvy.ktmongo.dsl.path.Field, ): Value> = of(this).takeLast(of(limit)) @@ -1950,7 +1950,7 @@ interface ArrayValueOperators : ValueOperators { @OptIn(LowLevelApi::class) @KtMongoDsl fun kotlin.reflect.KProperty1>.takeLast( - limit: kotlin.reflect.KProperty1, + limit: kotlin.reflect.KProperty1, ): Value> = of(this).takeLast(of(limit)) @@ -1982,7 +1982,7 @@ interface ArrayValueOperators : ValueOperators { @OptIn(LowLevelApi::class) @KtMongoDsl final inline fun kotlin.reflect.KProperty1>.takeLast( - limit: Number, + limit: Int, ): Value> = of(this).takeLast(of(limit)) @@ -2015,7 +2015,7 @@ interface ArrayValueOperators : ValueOperators { @OptIn(LowLevelApi::class) @KtMongoDsl fun Collection.takeLast( - limit: Value, + limit: Value, ): Value> = of(this).takeLast(limit) @@ -2048,7 +2048,7 @@ interface ArrayValueOperators : ValueOperators { @OptIn(LowLevelApi::class) @KtMongoDsl fun Collection.takeLast( - limit: opensavvy.ktmongo.dsl.path.Field, + limit: opensavvy.ktmongo.dsl.path.Field, ): Value> = of(this).takeLast(of(limit)) @@ -2081,7 +2081,7 @@ interface ArrayValueOperators : ValueOperators { @OptIn(LowLevelApi::class) @KtMongoDsl fun Collection.takeLast( - limit: kotlin.reflect.KProperty1, + limit: kotlin.reflect.KProperty1, ): Value> = of(this).takeLast(of(limit)) @@ -2114,7 +2114,7 @@ interface ArrayValueOperators : ValueOperators { @OptIn(LowLevelApi::class) @KtMongoDsl final inline fun Collection.takeLast( - limit: Number, + limit: Int, ): Value> = of(this).takeLast(of(limit)) diff --git a/dsl/src/commonMain/kotlin/aggregation/operators/ValueOperators.kt b/dsl/src/commonMain/kotlin/aggregation/operators/ValueOperators.kt index 67ae746c..eea87016 100644 --- a/dsl/src/commonMain/kotlin/aggregation/operators/ValueOperators.kt +++ b/dsl/src/commonMain/kotlin/aggregation/operators/ValueOperators.kt @@ -105,7 +105,7 @@ interface ValueOperators : FieldDsl { */ @OptIn(LowLevelApi::class) fun of(value: Result, type: KType): Value = - LiteralValue(value, context) + LiteralValue(value, context, type) /** * Refers to a Kotlin [value] within an [aggregation value][AggregationOperators]. @@ -349,12 +349,13 @@ private class FieldValue( private class LiteralValue( val value: Any?, context: BsonContext, + val type: KType, ) : AbstractValue(context) { @LowLevelApi override fun write(writer: BsonValueWriter) { writer.writeDocument { - writeObjectSafe("\$literal", value) + writeSafe("\$literal", value, type) } } } diff --git a/dsl/src/commonMain/kotlin/command/BulkWrite.kt b/dsl/src/commonMain/kotlin/command/BulkWrite.kt index f141a793..a455d412 100644 --- a/dsl/src/commonMain/kotlin/command/BulkWrite.kt +++ b/dsl/src/commonMain/kotlin/command/BulkWrite.kt @@ -34,6 +34,7 @@ import opensavvy.ktmongo.dsl.tree.AbstractBsonNode import opensavvy.ktmongo.dsl.tree.CompoundNode import opensavvy.ktmongo.dsl.tree.Node import opensavvy.ktmongo.dsl.tree.acceptAll +import kotlin.reflect.KType sealed interface AvailableInBulkWrite : Node, Command @@ -91,12 +92,17 @@ class BulkWrite private constructor( context: BsonContext, private val globalFilter: FilterQuery.() -> Unit, val options: BulkWriteOptions, + val documentType: KType, ) : Command, AbstractBsonNode(context), CompoundNode> { private val _operations = ArrayList>() val operations: Sequence> get() = _operations.asSequence() - constructor(context: BsonContext, globalFilter: FilterQuery.() -> Unit) : this(context, globalFilter, BulkWriteOptions(context)) + constructor( + context: BsonContext, + documentType: KType, + globalFilter: FilterQuery.() -> Unit, + ) : this(context, globalFilter, BulkWriteOptions(context), documentType) @LowLevelApi @DangerousMongoApi @@ -129,10 +135,11 @@ class BulkWrite private constructor( val child = BulkWrite( context = context, + documentType, globalFilter = { parent.globalFilter(this) filter() - } + }, ) child.operations() @@ -170,7 +177,7 @@ class BulkWrite private constructor( document: Document, options: InsertOneOptions.() -> Unit = {}, ) { - val model = InsertOne(context, document) + val model = InsertOne(context, document, documentType) model.options.options() @@ -415,7 +422,7 @@ class BulkWrite private constructor( filter: FilterQuery.() -> Unit = {}, document: Document, ) { - val model = ReplaceOne(context, document) + val model = ReplaceOne(context, document, documentType) model.options.options() model.filter.globalFilter() @@ -464,7 +471,7 @@ class BulkWrite private constructor( filter: FilterQuery.() -> Unit = {}, document: Document, ) { - val model = RepsertOne(context, document) + val model = RepsertOne(context, document, documentType) model.options.options() model.filter.globalFilter() @@ -482,7 +489,7 @@ class BulkWrite private constructor( when (operation) { is InsertOne<*> -> { writeInt32("insert", 0) - writeObjectSafe("document", operation.document) + writeSafe("document", operation.document) operation.options.writeTo(this) } @@ -503,7 +510,7 @@ class BulkWrite private constructor( writeDocument("filter") { operation.filter.writeTo(this) } - writeObjectSafe("updateMods", operation.document) + writeSafe("updateMods", operation.document) writeBoolean("multi", false) operation.options.writeTo(this) } @@ -513,7 +520,7 @@ class BulkWrite private constructor( writeDocument("filter") { operation.filter.writeTo(this) } - writeObjectSafe("updateMods", operation.document) + writeSafe("updateMods", operation.document) writeBoolean("multi", false) writeBoolean("upsert", true) operation.options.writeTo(this) diff --git a/dsl/src/commonMain/kotlin/command/Insert.kt b/dsl/src/commonMain/kotlin/command/Insert.kt index 746b8920..d080c2a0 100644 --- a/dsl/src/commonMain/kotlin/command/Insert.kt +++ b/dsl/src/commonMain/kotlin/command/Insert.kt @@ -27,6 +27,7 @@ import opensavvy.ktmongo.dsl.options.Options import opensavvy.ktmongo.dsl.options.OptionsHolder import opensavvy.ktmongo.dsl.options.WithWriteConcern import opensavvy.ktmongo.dsl.tree.AbstractBsonNode +import kotlin.reflect.KType /** * Inserting a single element in a collection. @@ -49,14 +50,19 @@ class InsertOne private constructor( context: BsonContext, val options: InsertOneOptions, val document: Document, + val documentType: KType, ) : Command, AbstractBsonNode(context), AvailableInBulkWrite { - constructor(context: BsonContext, document: Document) : this(context, InsertOneOptions(context), document) + constructor( + context: BsonContext, + document: Document, + documentType: KType, + ) : this(context, InsertOneOptions(context), document, documentType) @LowLevelApi override fun write(writer: BsonFieldWriter) = with(writer) { writeArray("documents") { - writeObjectSafe(document) + writeSafe(document, documentType) } options.writeTo(this) @@ -84,15 +90,20 @@ class InsertMany private constructor( context: BsonContext, val options: InsertManyOptions, val documents: List, + val documentType: KType, ) : Command, AbstractBsonNode(context) { - constructor(context: BsonContext, documents: List) : this(context, InsertManyOptions(context), documents) + constructor( + context: BsonContext, + documents: List, + documentType: KType, + ) : this(context, InsertManyOptions(context), documents, documentType) @LowLevelApi override fun write(writer: BsonFieldWriter) = with(writer) { writeArray("documents") { for (document in documents) { - writeObjectSafe(document) + writeSafe(document, documentType) } } diff --git a/dsl/src/commonMain/kotlin/command/Replace.kt b/dsl/src/commonMain/kotlin/command/Replace.kt index 6d57ba13..c7db171f 100644 --- a/dsl/src/commonMain/kotlin/command/Replace.kt +++ b/dsl/src/commonMain/kotlin/command/Replace.kt @@ -28,6 +28,7 @@ import opensavvy.ktmongo.dsl.options.OptionsHolder import opensavvy.ktmongo.dsl.options.WithWriteConcern import opensavvy.ktmongo.dsl.query.FilterQuery import opensavvy.ktmongo.dsl.tree.AbstractBsonNode +import kotlin.reflect.KType /** * Replaces a single element in a collection. @@ -50,10 +51,15 @@ class ReplaceOne private constructor( val options: ReplaceOptions, val filter: FilterQuery, val document: Document, + val documentType: KType, ) : AbstractBsonNode(context), Command, AvailableInBulkWrite { @OptIn(LowLevelApi::class) - constructor(context: BsonContext, document: Document) : this(context, ReplaceOptions(context), FilterQuery(context), document) + constructor( + context: BsonContext, + document: Document, + documentType: KType, + ) : this(context, ReplaceOptions(context), FilterQuery(context), document, documentType) @LowLevelApi override fun write(writer: BsonFieldWriter) = with(writer) { @@ -62,7 +68,7 @@ class ReplaceOne private constructor( writeDocument("q") { filter.writeTo(this) } - writeObjectSafe("u", document) + writeSafe("u", document, documentType) writeBoolean("upsert", false) writeBoolean("multi", false) } @@ -93,10 +99,15 @@ class RepsertOne private constructor( val options: ReplaceOptions, val filter: FilterQuery, val document: Document, + val documentType: KType, ) : AbstractBsonNode(context), Command, AvailableInBulkWrite { @OptIn(LowLevelApi::class) - constructor(context: BsonContext, document: Document) : this(context, ReplaceOptions(context), FilterQuery(context), document) + constructor( + context: BsonContext, + document: Document, + documentType: KType, + ) : this(context, ReplaceOptions(context), FilterQuery(context), document, documentType) @LowLevelApi override fun write(writer: BsonFieldWriter) = with(writer) { @@ -105,7 +116,7 @@ class RepsertOne private constructor( writeDocument("q") { filter.writeTo(this) } - writeObjectSafe("u", document) + writeSafe("u", document, documentType) writeBoolean("upsert", true) writeBoolean("multi", false) } diff --git a/dsl/src/commonMain/kotlin/query/FilterQuery.kt b/dsl/src/commonMain/kotlin/query/FilterQuery.kt index a4ce03b9..00194a73 100644 --- a/dsl/src/commonMain/kotlin/query/FilterQuery.kt +++ b/dsl/src/commonMain/kotlin/query/FilterQuery.kt @@ -19,6 +19,7 @@ package opensavvy.ktmongo.dsl.query +import opensavvy.ktmongo.bson.BsonDocument import opensavvy.ktmongo.bson.BsonType import opensavvy.ktmongo.bson.DEPRECATED_IN_BSON_SPEC import opensavvy.ktmongo.dsl.DangerousMongoApi @@ -907,7 +908,7 @@ interface FilterQuery : CompoundBsonNode, FieldDsl { fun Field>.isMapEmpty() { or { doesNotExist() - FieldImpl(path) eq context.buildDocument { } + FieldImpl(path).eq(context.buildDocument { }, typeOf()) } } @@ -1022,7 +1023,7 @@ interface FilterQuery : CompoundBsonNode, FieldDsl { @OptIn(LowLevelApi::class) @KtMongoDsl fun Field>.isMapNotEmpty() { - FieldImpl(path) gt context.buildDocument { } + FieldImpl(path).gt(context.buildDocument { }, typeOf()) } /** diff --git a/dsl/src/commonMain/kotlin/query/FilterQueryImpl.kt b/dsl/src/commonMain/kotlin/query/FilterQueryImpl.kt index a0d3e630..aea75e33 100644 --- a/dsl/src/commonMain/kotlin/query/FilterQueryImpl.kt +++ b/dsl/src/commonMain/kotlin/query/FilterQueryImpl.kt @@ -243,7 +243,7 @@ private class FilterQueryImpl( @OptIn(LowLevelApi::class, DangerousMongoApi::class) @KtMongoDsl override fun Field>.containsAll(values: Collection, type: KType) { - accept(ArrayAllBsonNodeNode(path, values, context)) + accept(ArrayAllBsonNodeNode(path, values, context, type)) } @LowLevelApi @@ -251,13 +251,14 @@ private class FilterQueryImpl( val path: Path, val values: Collection, context: BsonContext, + val type: KType, ) : FilterBsonNodeNode(context) { override fun write(writer: BsonFieldWriter) = with(writer) { writeDocument(path.toString()) { writeArray("\$all") { for (value in values) { - writeObjectSafe(value) + writeSafe(value, type) } } } diff --git a/dsl/src/commonMain/kotlin/query/FilterQueryPredicateImpl.kt b/dsl/src/commonMain/kotlin/query/FilterQueryPredicateImpl.kt index 885a54b5..0bbbd7d8 100644 --- a/dsl/src/commonMain/kotlin/query/FilterQueryPredicateImpl.kt +++ b/dsl/src/commonMain/kotlin/query/FilterQueryPredicateImpl.kt @@ -59,17 +59,18 @@ private class FilterQueryPredicateImpl( @OptIn(LowLevelApi::class, DangerousMongoApi::class) @KtMongoDsl override fun eq(value: T) { - accept(EqualityBsonNodeNode(value, context)) + accept(EqualityBsonNodeNode(value, context, type)) } @LowLevelApi private class EqualityBsonNodeNode( val value: T, context: BsonContext, + val type: KType, ) : PredicateBsonNodeNode(context) { override fun write(writer: BsonFieldWriter) { - writer.writeObjectSafe("\$eq", value) + writer.writeSafe("\$eq", value, type) } } @@ -79,17 +80,18 @@ private class FilterQueryPredicateImpl( @OptIn(LowLevelApi::class, DangerousMongoApi::class) @KtMongoDsl override fun ne(value: T) { - accept(InequalityBsonNodeNode(value, context)) + accept(InequalityBsonNodeNode(value, context, type)) } @LowLevelApi private class InequalityBsonNodeNode( val value: T, context: BsonContext, + val type: KType, ) : PredicateBsonNodeNode(context) { override fun write(writer: BsonFieldWriter) { - writer.writeObjectSafe("\$ne", value) + writer.writeSafe("\$ne", value, type) } } @@ -174,72 +176,76 @@ private class FilterQueryPredicateImpl( @OptIn(LowLevelApi::class, DangerousMongoApi::class) @KtMongoDsl override fun gt(value: T) { - accept(GtPredicateBsonNodeNode(value, context)) + accept(GtPredicateBsonNodeNode(value, context, type)) } @LowLevelApi private class GtPredicateBsonNodeNode( private val value: T, context: BsonContext, + val type: KType, ) : PredicateBsonNodeNode(context) { @LowLevelApi override fun write(writer: BsonFieldWriter) { - writer.writeObjectSafe("\$gt", value) + writer.writeSafe("\$gt", value, type) } } @OptIn(LowLevelApi::class, DangerousMongoApi::class) @KtMongoDsl override fun gte(value: T) { - accept(GtePredicateBsonNodeNode(value, context)) + accept(GtePredicateBsonNodeNode(value, context, type)) } @LowLevelApi private class GtePredicateBsonNodeNode( private val value: T, context: BsonContext, + val type: KType, ) : PredicateBsonNodeNode(context) { @LowLevelApi override fun write(writer: BsonFieldWriter) { - writer.writeObjectSafe("\$gte", value) + writer.writeSafe("\$gte", value, type) } } @OptIn(LowLevelApi::class, DangerousMongoApi::class) @KtMongoDsl override fun lt(value: T) { - accept(LtPredicateBsonNodeNode(value, context)) + accept(LtPredicateBsonNodeNode(value, context, type)) } @LowLevelApi private class LtPredicateBsonNodeNode( private val value: T, context: BsonContext, + val type: KType, ) : PredicateBsonNodeNode(context) { @LowLevelApi override fun write(writer: BsonFieldWriter) { - writer.writeObjectSafe("\$lt", value) + writer.writeSafe("\$lt", value, type) } } @OptIn(LowLevelApi::class, DangerousMongoApi::class) @KtMongoDsl override fun lte(value: T) { - accept(LtePredicateBsonNodeNode(value, context)) + accept(LtePredicateBsonNodeNode(value, context, type)) } @LowLevelApi private class LtePredicateBsonNodeNode( private val value: T, context: BsonContext, + val type: KType, ) : PredicateBsonNodeNode(context) { @LowLevelApi override fun write(writer: BsonFieldWriter) { - writer.writeObjectSafe("\$lte", value) + writer.writeSafe("\$lte", value, type) } } @@ -249,20 +255,21 @@ private class FilterQueryPredicateImpl( @OptIn(LowLevelApi::class, DangerousMongoApi::class) @KtMongoDsl override fun isOneOf(values: Collection) { - accept(OneOfPredicateBsonNodeNode(values, context)) + accept(OneOfPredicateBsonNodeNode(values, context, type)) } @LowLevelApi private class OneOfPredicateBsonNodeNode( val values: Collection, context: BsonContext, + val type: KType, ) : PredicateBsonNodeNode(context) { @LowLevelApi override fun write(writer: BsonFieldWriter) { writer.writeArray("\$in") { for (value in values) - writeObjectSafe(value) + writeSafe(value, type) } } } @@ -273,20 +280,21 @@ private class FilterQueryPredicateImpl( @OptIn(LowLevelApi::class, DangerousMongoApi::class) @KtMongoDsl override fun isNotOneOf(values: Collection) { - accept(NotOneOfPredicateExpressionNode(values, context)) + accept(NotOneOfPredicateExpressionNode(values, context, type)) } @LowLevelApi private class NotOneOfPredicateExpressionNode( val values: Collection, context: BsonContext, + val type: KType, ) : PredicateBsonNodeNode(context) { @LowLevelApi override fun write(writer: BsonFieldWriter) { writer.writeArray("\$nin") { for (value in values) - writeObjectSafe(value) + writeSafe(value, type) } } } diff --git a/dsl/src/commonMain/kotlin/query/UpdateQueryImpl.kt b/dsl/src/commonMain/kotlin/query/UpdateQueryImpl.kt index a7d4967e..f3cbb9c1 100644 --- a/dsl/src/commonMain/kotlin/query/UpdateQueryImpl.kt +++ b/dsl/src/commonMain/kotlin/query/UpdateQueryImpl.kt @@ -87,6 +87,14 @@ private class UpdateQueryImpl( return this } + private class Value( + val value: Any?, + val type: KType, + ) { + override fun toString(): String = + "Value($value, $type)" + } + @LowLevelApi private sealed class UpdateBsonNodeNode(context: BsonContext) : AbstractBsonNode(context) @@ -97,12 +105,12 @@ private class UpdateQueryImpl( @Suppress("INVISIBLE_REFERENCE") @KtMongoDsl override fun <@kotlin.internal.OnlyInputTypes V> Field.set(value: V, type: KType) { - accept(SetBsonNodeNode(listOf(this.path to value), context)) + accept(SetBsonNodeNode(listOf(this.path to Value(value, type)), context)) } @LowLevelApi private class SetBsonNodeNode( - val mappings: List>, + val mappings: List>, context: BsonContext, ) : UpdateBsonNodeNode(context) { @@ -112,7 +120,7 @@ private class UpdateQueryImpl( override fun write(writer: BsonFieldWriter) = with(writer) { writeDocument("\$set") { for ((field, value) in mappings) { - writeObjectSafe(field.toString(), value) + writeSafe(field.toString(), value.value, value.type) } } } @@ -125,12 +133,12 @@ private class UpdateQueryImpl( @Suppress("INVISIBLE_REFERENCE") @KtMongoDsl override fun <@kotlin.internal.OnlyInputTypes V> Field.setOnInsert(value: V, type: KType) { - accept(SetOnInsertBsonNodeNode(listOf(this.path to value), context)) + accept(SetOnInsertBsonNodeNode(listOf(this.path to Value(value, type)), context)) } @LowLevelApi private class SetOnInsertBsonNodeNode( - val mappings: List>, + val mappings: List>, context: BsonContext, ) : UpdateBsonNodeNode(context) { override fun simplify(): AbstractBsonNode? = @@ -139,7 +147,7 @@ private class UpdateQueryImpl( override fun write(writer: BsonFieldWriter) = with(writer) { writeDocument("\$setOnInsert") { for ((field, value) in mappings) { - writeObjectSafe(field.toString(), value) + writeSafe(field.toString(), value.value, value.type) } } } @@ -152,12 +160,12 @@ private class UpdateQueryImpl( @Suppress("INVISIBLE_REFERENCE") @KtMongoDsl override fun <@kotlin.internal.OnlyInputTypes V : Number> Field.inc(amount: V, type: KType) { - accept(IncrementBsonNodeNode(listOf(this.path to amount), context)) + accept(IncrementBsonNodeNode(listOf(this.path to Value(amount, type)), context)) } @LowLevelApi private class IncrementBsonNodeNode( - val mappings: List>, + val mappings: List>, context: BsonContext, ) : UpdateBsonNodeNode(context) { override fun simplify(): AbstractBsonNode? = @@ -166,7 +174,7 @@ private class UpdateQueryImpl( override fun write(writer: BsonFieldWriter) = with(writer) { writeDocument("\$inc") { for ((field, value) in mappings) { - writeObjectSafe(field.toString(), value) + writeSafe(field.toString(), value.value, value.type) } } } @@ -179,12 +187,12 @@ private class UpdateQueryImpl( @Suppress("INVISIBLE_REFERENCE") @KtMongoDsl override fun <@kotlin.internal.OnlyInputTypes V : Number> Field.mul(amount: V, type: KType) { - accept(MultiplyBsonNodeNode(listOf(this.path to amount), context)) + accept(MultiplyBsonNodeNode(listOf(this.path to Value(amount, type)), context)) } @LowLevelApi private class MultiplyBsonNodeNode( - val mappings: List>, + val mappings: List>, context: BsonContext, ) : UpdateBsonNodeNode(context) { override fun simplify(): AbstractBsonNode? = @@ -193,7 +201,7 @@ private class UpdateQueryImpl( override fun write(writer: BsonFieldWriter) = with(writer) { writeDocument("\$mul") { for ((field, value) in mappings) { - writeObjectSafe(field.toString(), value) + writeSafe(field.toString(), value.value, value.type) } } } @@ -233,12 +241,12 @@ private class UpdateQueryImpl( @Suppress("INVISIBLE_REFERENCE") @KtMongoDsl override fun <@kotlin.internal.OnlyInputTypes V : Comparable> Field.min(value: V, type: KType) { - accept(MinBsonNodeNode(listOf(this.path to value), context)) + accept(MinBsonNodeNode(listOf(this.path to Value(value, type)), context)) } @LowLevelApi private class MinBsonNodeNode( - val mappings: List>, + val mappings: List>, context: BsonContext, ) : UpdateBsonNodeNode(context) { override fun simplify(): AbstractBsonNode? = @@ -247,7 +255,7 @@ private class UpdateQueryImpl( override fun write(writer: BsonFieldWriter) = with(writer) { writeDocument("\$min") { for ((field, value) in mappings) { - writeObjectSafe(field.toString(), value) + writeSafe(field.toString(), value.value, value.type) } } } @@ -260,12 +268,12 @@ private class UpdateQueryImpl( @Suppress("INVISIBLE_REFERENCE") @KtMongoDsl override fun <@kotlin.internal.OnlyInputTypes V : Comparable> Field.max(value: V, type: KType) { - accept(MaxBsonNodeNode(listOf(this.path to value), context)) + accept(MaxBsonNodeNode(listOf(this.path to Value(value, type)), context)) } @LowLevelApi private class MaxBsonNodeNode( - val mappings: List>, + val mappings: List>, context: BsonContext, ) : UpdateBsonNodeNode(context) { override fun simplify(): AbstractBsonNode? = @@ -274,7 +282,7 @@ private class UpdateQueryImpl( override fun write(writer: BsonFieldWriter) = with(writer) { writeDocument("\$max") { for ((field, value) in mappings) { - writeObjectSafe(field.toString(), value) + writeSafe(field.toString(), value.value, value.type) } } } @@ -353,12 +361,12 @@ private class UpdateQueryImpl( @OptIn(DangerousMongoApi::class, LowLevelApi::class) override fun Field>.addToSet(value: V, type: KType) { - accept(AddToSetBsonNode(listOf(this.path to value), context)) + accept(AddToSetBsonNode(listOf(this.path to Value(value, type)), context)) } @LowLevelApi private class AddToSetBsonNode( - val mappings: List>, + val mappings: List>, context: BsonContext, ) : UpdateBsonNodeNode(context) { @@ -374,12 +382,12 @@ private class UpdateQueryImpl( writeDocument($$"$addToSet") { for ((field, values) in groupedMappings) { if (values.size == 1) - writeObjectSafe(field.toString(), values.single()) + writeSafe(field.toString(), values.single().value, values.single().type) else writeDocument(field.toString()) { writeArray($$"$each") { for (value in values) - writeObjectSafe(value) + writeSafe(value.value, value.type) } } } diff --git a/dsl/src/commonTest/kotlin/command/BulkWriteTest.kt b/dsl/src/commonTest/kotlin/command/BulkWriteTest.kt index d3ea0281..a34226c3 100644 --- a/dsl/src/commonTest/kotlin/command/BulkWriteTest.kt +++ b/dsl/src/commonTest/kotlin/command/BulkWriteTest.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, OpenSavvy and contributors. + * Copyright (c) 2025-2026, 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. @@ -20,6 +20,7 @@ import opensavvy.ktmongo.dsl.options.WriteConcern import opensavvy.ktmongo.dsl.query.shouldBeBson import opensavvy.ktmongo.dsl.query.testContext import opensavvy.prepared.runner.testballoon.preparedSuite +import kotlin.reflect.typeOf import kotlin.time.Duration.Companion.minutes val BulkWriteTest by preparedSuite { @@ -31,7 +32,7 @@ val BulkWriteTest by preparedSuite { ) test("bulkWrite") { - BulkWrite(testContext(), {}).apply { + BulkWrite(testContext(), typeOf(), {}).apply { updateOne( filter = { Target::name eq "Daniel" diff --git a/dsl/src/commonTest/kotlin/command/InsertTest.kt b/dsl/src/commonTest/kotlin/command/InsertTest.kt index 14c674d0..ffbbf7e6 100644 --- a/dsl/src/commonTest/kotlin/command/InsertTest.kt +++ b/dsl/src/commonTest/kotlin/command/InsertTest.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, OpenSavvy and contributors. + * Copyright (c) 2025-2026, 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. @@ -23,6 +23,7 @@ import opensavvy.ktmongo.dsl.options.WriteConcern import opensavvy.ktmongo.dsl.query.shouldBeBson import opensavvy.ktmongo.dsl.query.testContext import opensavvy.prepared.runner.testballoon.preparedSuite +import kotlin.reflect.typeOf val InsertTest by preparedSuite { @@ -32,7 +33,7 @@ val InsertTest by preparedSuite { writeString("name", "Daniel") } as opensavvy.ktmongo.bson.official.BsonDocument - InsertOne(testContext(), daniel.raw).apply { + InsertOne(testContext(), daniel.raw, typeOf()).apply { options.apply { writeConcern(WriteConcern.FireAndForget) } @@ -67,7 +68,7 @@ val InsertTest by preparedSuite { writeString("name", "Alice") } as opensavvy.ktmongo.bson.official.BsonDocument - InsertMany(testContext(), listOf(daniel.raw, fred.raw, alice.raw)).apply { + InsertMany(testContext(), listOf(daniel.raw, fred.raw, alice.raw), typeOf()).apply { options.apply { writeConcern(WriteConcern.Primary) } -- 2.51.2