DSL Based MongoDB driver wrapper for kotlin with an optional schema system.
Note: this README is demonstrating how to use the ORM module. But, the ORM module is DEPRECATED and a demonstration of using MOONKIT module is coming in a day called "Someday"
The main way of installing this library is
using jitpack.io
repositories {
// ...
mavenCentral()
maven { url = uri("https://jitpack.io") }
}
dependencies {
// Replace TAG with the desired version
implementation("org.cufy.serialization:cufyorg-bson:TAG")
implementation("org.cufy.moonkit:cufyorg-mongodb:TAG")
implementation("org.cufy.moonkit:cufyorg-moonkit-orm:TAG")
}
The following is how to do the monkt connection on the default monkt instance.
suspend fun foo() {
Monkt.connect("mongodb://localhost:27017", "Monkt")
// Initialization can be done later
thread {
runBlocking {
Monkt += Model1
Monkt += Model2
Monkt.init()
}
}
}
Monkt was made to mimic the style of mongoose as possible. Obviously a real mongoose in kotlin is impossible to be maid since type-unions are not a supported thing in kotlin. But, the thing that kotlin has instead is extension functions. So, monkt took a good advantage of that.
For example, the following with mongoose:
export interface Entity extends Document {
value?: string;
friendId: ObjectId;
list: string[];
}
export const EntitySchema = new Schema<Entity>({
value: {
type: SchemaTypes.String,
default: () => "Initialized",
validate: value => value !== "Invalid",
immutable: value => value === "Immutable"
},
friendId: {
type: SchemaTypes.ObjectId,
ref: () => "Entity",
exists: true // using module 'mongoose-extra-validators'
},
list: {
type: [SchemaTypes.String],
default: () => ["FirstElement"]
}
});
export const EntityModel = model("Entity", EntitySchema, "Entity");
Has the following equivalent with monkt:
class Entity : Document {
var value: String? = null
lateinit var friendId: Id<Entity>
lateinit var list: List<String>
}
val EntitySchema = ObjectSchema(::Entity) {
field(Entity::value) {
schema { NullableSchema(StringSchema) }
default { "Initialized" }
validate { value != "Invalid" }
immutable { value == "Immutable" }
}
field(Entity::friendId) {
schema { IdSchema() }
exists { EntityModel }
}
field(Entity::list) {
schema { ArraySchema(StringSchema) }
default { mutableListOf("FirstElement") }
}
}
val EntityModel: Model<Entity> = Model("Entity", EntitySchema)
The model is a tricky one, since in mongoose the model has mongoose internal stuff with javascript specific wizardry which is not even needed in monkt. But, still the developer experience is the first priority here in monkt. So, the code appears the same, but internally it is not.
For example, the following code with mongoose:
async function useEntityModel() {
const entity = new EntityModel()
await EntityModel.create({
value: "SomeValue"
})
await EntityModel.findOne({
value: "SomeValue"
})
}
Has the following equivalent with monkt:
suspend fun useEntityModel() {
val entity = EntityModel()
EntityModel.create({
Entity::value by "SomeValue"
// equilvilant:
"value" by "SomeValue"
})
EntityModel.findOne({
Entity::value by "SomeValue"
// equilvilant:
"value" by "SomeValue"
})
}
One of the best things about mongoose is the interface
Document
that has shortcuts for saving, deleting and
validating values without the need to know the client,
database or collection they came from.
This is one of the easiest to mimic features that was
implemented in monkt.
For example, the following with mongoose:
async function useEntityDocument(entity: Entity) {
await entity.validate()
await entity.save()
await entity.remove()
}
Has the following equivalent with monkt:
suspend fun useEntityDocument(entity: Entity) {
entity.validate()
entity.save()
entity.delete()
}
This feature doesn't event need to be implemented in monkt. The best thing about kotlin extension functions is that anyone can write their own extension function.
The following is an example for extension functions:
// example virtual value
val Entity.firstElement: String?
get() = list.firstOrNull()
// example of fantom value
val Entity.fantomValue by Document.fantom()
// example member function
suspend fun Entity.findFriend(): Entity? {
return model.findOne({
"_id" by friendId
})
}
// example static function
suspend fun Model<Entity>.findByValue(value: String): Entity? {
return findOne({
Entity::value by value
})
}