This repository has been archived by the owner on Oct 15, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #12 from lsafer-meemer/main
feat(op): OpBucket
- Loading branch information
Showing
3 changed files
with
306 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
/* | ||
* Copyright 2023 cufy.org and meemer.com | ||
* | ||
* 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 org.cufy.monop.gridfs | ||
|
||
import org.cufy.mongodb.gridfs.MongoBucket | ||
import org.cufy.monop.Op | ||
import org.cufy.monop.OpClient | ||
|
||
/* ============= ------------------ ============= */ | ||
|
||
/** | ||
* A type of ops that is focused on [MongoBucket]. | ||
* This type of operations only produces operations | ||
* that are of type [BucketOperation]. | ||
* | ||
* @author LSafer | ||
* @since 2.0.0 | ||
*/ | ||
interface BucketOp<T> : Op<T> { | ||
/** | ||
* The name of the database of the bucket | ||
* to operate on. | ||
* Set to `null` to use [OpClient.defaultDatabase]. | ||
* | ||
* @since 2.0.0 | ||
*/ | ||
val database: String? | ||
|
||
/** | ||
* The name of the bucket this operation | ||
* is targeting. | ||
*/ | ||
val bucket: String | ||
|
||
override fun createOperation(): BucketOperation<T> | ||
} | ||
|
||
private fun BucketOp<*>.inferToString(): String { | ||
val name = this::class.simpleName ?: "BucketOp" | ||
val address = System.identityHashCode(this).toString(16) | ||
return "$name($database, $bucket, ...)@$address" | ||
} | ||
|
||
/* ============= ------------------ ============= */ | ||
|
||
/** | ||
* Create a custom [BucketOp] with the given [block] being its default behaviour. | ||
* | ||
* @param bucket the name of the bucket for the operation. | ||
* @param database name of the database for the operation. (null for [OpClient.defaultDatabase]) | ||
* @since 2.0.0 | ||
*/ | ||
fun <T> BucketOp(bucket: String, database: String? = null, block: suspend (MongoBucket) -> T): BucketOp<T> { | ||
return object : BucketOp<T> { | ||
override val database = database | ||
override val bucket = bucket | ||
|
||
override fun toString() = inferToString() | ||
|
||
override fun createOperation(): BucketOperation<T> = | ||
BucketOperation(bucket, database, block) | ||
} | ||
} | ||
|
||
/* ============= ------------------ ============= */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
/* | ||
* Copyright 2023 cufy.org and meemer.com | ||
* | ||
* 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 org.cufy.monop.gridfs | ||
|
||
import kotlinx.coroutines.* | ||
import org.cufy.mongodb.gridfs.MongoBucket | ||
import org.cufy.mongodb.gridfs.createMongoBucket | ||
import org.cufy.monop.* | ||
|
||
/* ============= ------------------ ============= */ | ||
|
||
/** | ||
* A type of operations that is focused on [MongoBucket]. | ||
* This type of operations have a default behaviour that only | ||
* require an instance of [MongoBucket]. | ||
* | ||
* @author LSafer | ||
* @since 2.0.0 | ||
*/ | ||
interface BucketOperation<T> : Operation<T> { | ||
/** | ||
* The name of the database of the bucket | ||
* to operate on. | ||
* Set to `null` to use [OpClient.defaultDatabase]. | ||
* | ||
* @since 2.0.0 | ||
*/ | ||
val database: String? | ||
|
||
/** | ||
* The name of the bucket this operation | ||
* is targeting. | ||
*/ | ||
val bucket: String | ||
|
||
/** | ||
* The default behaviour of this operation. | ||
* | ||
* **NOTE: errors throw by this function won't be caught safely.** | ||
* | ||
* @since 2.0.0 | ||
*/ | ||
suspend fun completeWithDefaultBehaviour(bucket: MongoBucket) | ||
} | ||
|
||
private fun BucketOperation<*>.inferToString(): String { | ||
val name = this::class.simpleName ?: "BucketOperation" | ||
val address = System.identityHashCode(this).toString(16) | ||
return "$name($database, $bucket, ...)@$address" | ||
} | ||
|
||
/* ============= ------------------ ============= */ | ||
|
||
/** | ||
* Create a custom [BucketOperation] with the given [block] being its default behaviour. | ||
* | ||
* @param bucket the name of the bucket for the operation. | ||
* @param database name of the database for the operation. (null for [OpClient.defaultDatabase]) | ||
* @since 2.0.0 | ||
*/ | ||
fun <T> BucketOperation(bucket: String, database: String? = null, block: suspend (MongoBucket) -> T): BucketOperation<T> { | ||
return object : BucketOperation<T>, CompletableDeferred<T> by CompletableDeferred() { | ||
override val database = database | ||
override val bucket = bucket | ||
|
||
override fun toString() = inferToString() | ||
|
||
override suspend fun completeWithDefaultBehaviour(bucket: MongoBucket) { | ||
completeWith(runCatching { block(bucket) }) | ||
} | ||
} | ||
} | ||
|
||
/* ============= ------------------ ============= */ | ||
|
||
/** | ||
* An operator performing operations of type [BucketOperation] in parallel | ||
* using [BucketOperation.completeWithDefaultBehaviour]. | ||
* | ||
* @author LSafer | ||
* @since 2.0.0 | ||
*/ | ||
@ExperimentalMonopApi | ||
val BucketOperator = createOperatorForType<BucketOperation<*>> { operations -> | ||
val leftovers = mutableSetOf<BucketOperation<*>>() | ||
for ((databaseName, databaseOperations) in operations.groupBy { it.database }) { | ||
val database = databaseOrDefaultDatabase(databaseName) | ||
|
||
// if databaseName is null yet no default database is set | ||
if (database == null) { | ||
leftovers += databaseOperations | ||
continue | ||
} | ||
|
||
for ((bucketName, bucketOperations) in databaseOperations.groupBy { it.bucket }) { | ||
val bucket = createMongoBucket(database, bucketName) | ||
|
||
bucketOperations.forEach { | ||
CoroutineScope(Dispatchers.IO).launch { | ||
it.completeWithDefaultBehaviour(bucket) | ||
} | ||
} | ||
} | ||
} | ||
|
||
leftovers | ||
} | ||
|
||
/* ============= ------------------ ============= */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
/* | ||
* Copyright 2023 cufy.org and meemer.com | ||
* | ||
* 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 org.cufy.monop.gridfs | ||
|
||
import org.cufy.mongodb.gridfs.MongoBucket | ||
import org.cufy.mongodb.gridfs.createMongoBucket | ||
import org.cufy.monop.Op | ||
import org.cufy.monop.OpClient | ||
import org.cufy.monop.databaseOrDefaultDatabase | ||
|
||
/* ============= ------------------ ============= */ | ||
|
||
/** | ||
* A convenient class that holds bare minimal | ||
* data needed for using some bucket. | ||
* | ||
* @author LSafer | ||
* @since 2.0.0 | ||
*/ | ||
interface OpBucket { | ||
/** | ||
* The default bucket. | ||
*/ | ||
companion object : OpBucket { | ||
override val name = "fs" | ||
} | ||
|
||
/** | ||
* The name of the database of the bucket | ||
* to operate on. | ||
* Set to `null` to use [OpClient.defaultDatabase]. | ||
* | ||
* @since 2.0.0 | ||
*/ | ||
val database: String? get() = null | ||
|
||
/** | ||
* The bucket name. | ||
* | ||
* @since 2.0.0 | ||
*/ | ||
val name: String get() = inferName() | ||
} | ||
|
||
private fun OpBucket.inferName(): String { | ||
return this::class.simpleName ?: error("Cannot infer bucket name for $this") | ||
} | ||
|
||
private fun OpBucket.inferToString(): String { | ||
return "OpBucket($database, $name)" | ||
} | ||
|
||
/* ============= ------------------ ============= */ | ||
|
||
/** | ||
* Construct a new [OpBucket] with the given [name] and [database]. | ||
* | ||
* @since 2.0.0 | ||
*/ | ||
fun OpBucket(name: String, database: String? = null): OpBucket { | ||
return object : OpBucket { | ||
override val database = database | ||
override val name = name | ||
|
||
override fun toString() = inferToString() | ||
} | ||
} | ||
|
||
/* ============= ------------------ ============= */ | ||
|
||
/** | ||
* Return a [MongoBucket] instance corresponding | ||
* to this bucket using the given [client]. | ||
*/ | ||
suspend fun OpBucket.get(client: OpClient = OpClient): MongoBucket { | ||
val database = client.databaseOrDefaultDatabase(database) | ||
// if this.database is null yet no default database is set | ||
database ?: error("Bucket requires default database yet default database not set.") | ||
return createMongoBucket(database, name) | ||
} | ||
|
||
/** | ||
* Create an [Op] that executes the given [block] | ||
* with a [MongoBucket] corresponding to this | ||
* bucket. | ||
* | ||
* @since 2.0.0 | ||
*/ | ||
fun <T> OpBucket.op(block: suspend MongoBucket.() -> T): Op<T> { | ||
return BucketOp(name, database, block) | ||
} | ||
|
||
/* ============= ------------------ ============= */ |