effect-mongodb 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Collection/package.json +6 -0
- package/Db/package.json +6 -0
- package/DocumentCollection/package.json +6 -0
- package/DocumentFindCursor/package.json +6 -0
- package/FindCursor/package.json +6 -0
- package/LICENSE +21 -0
- package/MongoClient/package.json +6 -0
- package/MongoError/package.json +6 -0
- package/README.md +28 -0
- package/dist/cjs/Collection.js +33 -0
- package/dist/cjs/Collection.js.map +1 -0
- package/dist/cjs/Db.js +36 -0
- package/dist/cjs/Db.js.map +1 -0
- package/dist/cjs/DocumentCollection.js +29 -0
- package/dist/cjs/DocumentCollection.js.map +1 -0
- package/dist/cjs/DocumentFindCursor.js +41 -0
- package/dist/cjs/DocumentFindCursor.js.map +1 -0
- package/dist/cjs/FindCursor.js +65 -0
- package/dist/cjs/FindCursor.js.map +1 -0
- package/dist/cjs/MongoClient.js +20 -0
- package/dist/cjs/MongoClient.js.map +1 -0
- package/dist/cjs/MongoError.js +33 -0
- package/dist/cjs/MongoError.js.map +1 -0
- package/dist/cjs/index.js +23 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/internal/version.js +14 -0
- package/dist/cjs/internal/version.js.map +1 -0
- package/dist/dts/Collection.d.ts +37 -0
- package/dist/dts/Collection.d.ts.map +1 -0
- package/dist/dts/Db.d.ts +30 -0
- package/dist/dts/Db.d.ts.map +1 -0
- package/dist/dts/DocumentCollection.d.ts +39 -0
- package/dist/dts/DocumentCollection.d.ts.map +1 -0
- package/dist/dts/DocumentFindCursor.d.ts +40 -0
- package/dist/dts/DocumentFindCursor.d.ts.map +1 -0
- package/dist/dts/FindCursor.d.ts +40 -0
- package/dist/dts/FindCursor.d.ts.map +1 -0
- package/dist/dts/MongoClient.d.ts +21 -0
- package/dist/dts/MongoClient.d.ts.map +1 -0
- package/dist/dts/MongoError.d.ts +21 -0
- package/dist/dts/MongoError.d.ts.map +1 -0
- package/dist/dts/index.d.ts +29 -0
- package/dist/dts/index.d.ts.map +1 -0
- package/dist/dts/internal/version.d.ts +3 -0
- package/dist/dts/internal/version.d.ts.map +1 -0
- package/dist/esm/Collection.js +24 -0
- package/dist/esm/Collection.js.map +1 -0
- package/dist/esm/Db.js +25 -0
- package/dist/esm/Db.js.map +1 -0
- package/dist/esm/DocumentCollection.js +20 -0
- package/dist/esm/DocumentCollection.js.map +1 -0
- package/dist/esm/DocumentFindCursor.js +30 -0
- package/dist/esm/DocumentFindCursor.js.map +1 -0
- package/dist/esm/FindCursor.js +52 -0
- package/dist/esm/FindCursor.js.map +1 -0
- package/dist/esm/MongoClient.js +10 -0
- package/dist/esm/MongoClient.js.map +1 -0
- package/dist/esm/MongoError.js +23 -0
- package/dist/esm/MongoError.js.map +1 -0
- package/dist/esm/index.js +29 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/internal/version.js +6 -0
- package/dist/esm/internal/version.js.map +1 -0
- package/dist/esm/package.json +4 -0
- package/package.json +93 -0
- package/src/Collection.ts +130 -0
- package/src/Db.ts +79 -0
- package/src/DocumentCollection.ts +128 -0
- package/src/DocumentFindCursor.ts +90 -0
- package/src/FindCursor.ts +138 -0
- package/src/MongoClient.ts +35 -0
- package/src/MongoError.ts +40 -0
- package/src/index.ts +34 -0
- package/src/internal/version.ts +7 -0
package/package.json
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "effect-mongodb",
|
|
3
|
+
"version": "0.0.2",
|
|
4
|
+
"description": "A MongoDB toolkit for Effect",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "https://github.com/doubleloop-io/effect-mongodb",
|
|
9
|
+
"directory": "packages/effect-mongodb"
|
|
10
|
+
},
|
|
11
|
+
"sideEffects": [],
|
|
12
|
+
"author": "doubleloop.io",
|
|
13
|
+
"homepage": "https://github.com/doubleloop-io/effect-mongodb",
|
|
14
|
+
"peerDependencies": {
|
|
15
|
+
"@effect/schema": "^0.73.4",
|
|
16
|
+
"effect": "^3.8.3",
|
|
17
|
+
"mongodb": "^6.8.0"
|
|
18
|
+
},
|
|
19
|
+
"publishConfig": {
|
|
20
|
+
"provenance": true
|
|
21
|
+
},
|
|
22
|
+
"main": "./dist/cjs/index.js",
|
|
23
|
+
"module": "./dist/esm/index.js",
|
|
24
|
+
"types": "./dist/dts/index.d.ts",
|
|
25
|
+
"exports": {
|
|
26
|
+
"./package.json": "./package.json",
|
|
27
|
+
".": {
|
|
28
|
+
"types": "./dist/dts/index.d.ts",
|
|
29
|
+
"import": "./dist/esm/index.js",
|
|
30
|
+
"default": "./dist/cjs/index.js"
|
|
31
|
+
},
|
|
32
|
+
"./Collection": {
|
|
33
|
+
"types": "./dist/dts/Collection.d.ts",
|
|
34
|
+
"import": "./dist/esm/Collection.js",
|
|
35
|
+
"default": "./dist/cjs/Collection.js"
|
|
36
|
+
},
|
|
37
|
+
"./Db": {
|
|
38
|
+
"types": "./dist/dts/Db.d.ts",
|
|
39
|
+
"import": "./dist/esm/Db.js",
|
|
40
|
+
"default": "./dist/cjs/Db.js"
|
|
41
|
+
},
|
|
42
|
+
"./DocumentCollection": {
|
|
43
|
+
"types": "./dist/dts/DocumentCollection.d.ts",
|
|
44
|
+
"import": "./dist/esm/DocumentCollection.js",
|
|
45
|
+
"default": "./dist/cjs/DocumentCollection.js"
|
|
46
|
+
},
|
|
47
|
+
"./DocumentFindCursor": {
|
|
48
|
+
"types": "./dist/dts/DocumentFindCursor.d.ts",
|
|
49
|
+
"import": "./dist/esm/DocumentFindCursor.js",
|
|
50
|
+
"default": "./dist/cjs/DocumentFindCursor.js"
|
|
51
|
+
},
|
|
52
|
+
"./FindCursor": {
|
|
53
|
+
"types": "./dist/dts/FindCursor.d.ts",
|
|
54
|
+
"import": "./dist/esm/FindCursor.js",
|
|
55
|
+
"default": "./dist/cjs/FindCursor.js"
|
|
56
|
+
},
|
|
57
|
+
"./MongoClient": {
|
|
58
|
+
"types": "./dist/dts/MongoClient.d.ts",
|
|
59
|
+
"import": "./dist/esm/MongoClient.js",
|
|
60
|
+
"default": "./dist/cjs/MongoClient.js"
|
|
61
|
+
},
|
|
62
|
+
"./MongoError": {
|
|
63
|
+
"types": "./dist/dts/MongoError.d.ts",
|
|
64
|
+
"import": "./dist/esm/MongoError.js",
|
|
65
|
+
"default": "./dist/cjs/MongoError.js"
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
"typesVersions": {
|
|
69
|
+
"*": {
|
|
70
|
+
"Collection": [
|
|
71
|
+
"./dist/dts/Collection.d.ts"
|
|
72
|
+
],
|
|
73
|
+
"Db": [
|
|
74
|
+
"./dist/dts/Db.d.ts"
|
|
75
|
+
],
|
|
76
|
+
"DocumentCollection": [
|
|
77
|
+
"./dist/dts/DocumentCollection.d.ts"
|
|
78
|
+
],
|
|
79
|
+
"DocumentFindCursor": [
|
|
80
|
+
"./dist/dts/DocumentFindCursor.d.ts"
|
|
81
|
+
],
|
|
82
|
+
"FindCursor": [
|
|
83
|
+
"./dist/dts/FindCursor.d.ts"
|
|
84
|
+
],
|
|
85
|
+
"MongoClient": [
|
|
86
|
+
"./dist/dts/MongoClient.d.ts"
|
|
87
|
+
],
|
|
88
|
+
"MongoError": [
|
|
89
|
+
"./dist/dts/MongoError.d.ts"
|
|
90
|
+
]
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @since 0.0.1
|
|
3
|
+
*/
|
|
4
|
+
import type * as ParseResult from "@effect/schema/ParseResult"
|
|
5
|
+
import * as Schema from "@effect/schema/Schema"
|
|
6
|
+
import * as Data from "effect/Data"
|
|
7
|
+
import * as Effect from "effect/Effect"
|
|
8
|
+
import * as F from "effect/Function"
|
|
9
|
+
import * as O from "effect/Option"
|
|
10
|
+
import type {
|
|
11
|
+
BulkWriteOptions,
|
|
12
|
+
Collection as MongoCollection,
|
|
13
|
+
Document,
|
|
14
|
+
Filter,
|
|
15
|
+
FindOptions as MongoFindOptions,
|
|
16
|
+
InsertManyResult,
|
|
17
|
+
InsertOneOptions,
|
|
18
|
+
InsertOneResult
|
|
19
|
+
} from "mongodb"
|
|
20
|
+
import * as FindCursor from "./FindCursor.js"
|
|
21
|
+
import * as MongoError from "./MongoError.js"
|
|
22
|
+
|
|
23
|
+
export class Collection<A extends Document, I extends Document = A, R = never> extends Data.TaggedClass("Collection")<{
|
|
24
|
+
collection: MongoCollection
|
|
25
|
+
schema: Schema.Schema<A, I, R>
|
|
26
|
+
}> {
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export type FindOptions = Omit<MongoFindOptions, "projection">
|
|
30
|
+
|
|
31
|
+
export const find: {
|
|
32
|
+
(
|
|
33
|
+
options?: FindOptions
|
|
34
|
+
): <A extends Document, I extends Document = A, R = never>(
|
|
35
|
+
collection: Collection<A, I, R>
|
|
36
|
+
) => FindCursor.FindCursor<A, I, R>
|
|
37
|
+
<A extends Document, I extends Document = A, R = never>(
|
|
38
|
+
collection: Collection<A, I, R>,
|
|
39
|
+
options?: FindOptions
|
|
40
|
+
): FindCursor.FindCursor<A, I, R>
|
|
41
|
+
} = F.dual(
|
|
42
|
+
(args) => isCollection(args[0]),
|
|
43
|
+
<A extends Document, I extends Document = A, R = never>(
|
|
44
|
+
collection: Collection<A, I, R>,
|
|
45
|
+
options?: FindOptions
|
|
46
|
+
): FindCursor.FindCursor<A, I, R> =>
|
|
47
|
+
new FindCursor.FindCursor<A, I, R>({
|
|
48
|
+
cursor: collection.collection.find({}, options),
|
|
49
|
+
schema: collection.schema
|
|
50
|
+
})
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
export const findOne: {
|
|
54
|
+
<A extends Document, I extends Document = A, R = never>(
|
|
55
|
+
filter: Filter<I>,
|
|
56
|
+
options?: FindOptions
|
|
57
|
+
): (
|
|
58
|
+
collection: Collection<A, I, R>
|
|
59
|
+
) => Effect.Effect<O.Option<Document>, MongoError.MongoError | ParseResult.ParseError, R>
|
|
60
|
+
<A extends Document, I extends Document = A, R = never>(
|
|
61
|
+
collection: Collection<A, I, R>,
|
|
62
|
+
filter: Filter<I>,
|
|
63
|
+
options?: FindOptions
|
|
64
|
+
): Effect.Effect<O.Option<Document>, MongoError.MongoError | ParseResult.ParseError, R>
|
|
65
|
+
} = F.dual(
|
|
66
|
+
(args) => isCollection(args[0]),
|
|
67
|
+
<A extends Document, I extends Document = A, R = never>(
|
|
68
|
+
collection: Collection<A, I, R>,
|
|
69
|
+
filter: Filter<I>,
|
|
70
|
+
options?: FindOptions
|
|
71
|
+
): Effect.Effect<O.Option<A>, MongoError.MongoError | ParseResult.ParseError, R> =>
|
|
72
|
+
Effect.gen(function*(_) {
|
|
73
|
+
const value = yield* _(Effect.promise(() => collection.collection.findOne(filter as Filter<Document>, options)))
|
|
74
|
+
if (value !== null) return O.some(yield* _(Schema.decodeUnknown(collection.schema)(value)))
|
|
75
|
+
return O.none()
|
|
76
|
+
}).pipe(
|
|
77
|
+
Effect.catchAllDefect(MongoError.mongoErrorDie<O.Option<A>>("findOne error"))
|
|
78
|
+
)
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
export const insertOne: {
|
|
82
|
+
<A extends Document, I extends Document = A, R = never>(
|
|
83
|
+
doc: A,
|
|
84
|
+
options?: InsertOneOptions
|
|
85
|
+
): (
|
|
86
|
+
collection: Collection<A, I, R>
|
|
87
|
+
) => Effect.Effect<InsertOneResult, MongoError.MongoError | ParseResult.ParseError, R>
|
|
88
|
+
<A extends Document, I extends Document = A, R = never>(
|
|
89
|
+
collection: Collection<A, I, R>,
|
|
90
|
+
doc: A,
|
|
91
|
+
options?: InsertOneOptions
|
|
92
|
+
): Effect.Effect<InsertOneResult, MongoError.MongoError | ParseResult.ParseError, R>
|
|
93
|
+
} = F.dual((args) => isCollection(args[0]), <A extends Document, I extends Document = A, R = never>(
|
|
94
|
+
collection: Collection<A, I, R>,
|
|
95
|
+
doc: A,
|
|
96
|
+
options?: InsertOneOptions
|
|
97
|
+
): Effect.Effect<InsertOneResult, MongoError.MongoError | ParseResult.ParseError, R> =>
|
|
98
|
+
F.pipe(
|
|
99
|
+
Schema.encode(collection.schema)(doc),
|
|
100
|
+
Effect.flatMap((doc) => Effect.promise(() => collection.collection.insertOne(doc, options))),
|
|
101
|
+
Effect.catchAllDefect(MongoError.mongoErrorDie<InsertOneResult>("insertOne error"))
|
|
102
|
+
))
|
|
103
|
+
|
|
104
|
+
export const insertMany: {
|
|
105
|
+
<A extends Document, I extends Document = A, R = never>(
|
|
106
|
+
docs: Array<A>,
|
|
107
|
+
options?: BulkWriteOptions
|
|
108
|
+
): (
|
|
109
|
+
collection: Collection<A, I, R>
|
|
110
|
+
) => Effect.Effect<InsertManyResult, MongoError.MongoError | ParseResult.ParseError, R>
|
|
111
|
+
<A extends Document, I extends Document = A, R = never>(
|
|
112
|
+
collection: Collection<A, I, R>,
|
|
113
|
+
docs: Array<A>,
|
|
114
|
+
options?: BulkWriteOptions
|
|
115
|
+
): Effect.Effect<InsertManyResult, MongoError.MongoError | ParseResult.ParseError, R>
|
|
116
|
+
} = F.dual((args) => isCollection(args[0]), <A extends Document, I extends Document = A, R = never>(
|
|
117
|
+
collection: Collection<A, I, R>,
|
|
118
|
+
docs: Array<A>,
|
|
119
|
+
options?: BulkWriteOptions
|
|
120
|
+
): Effect.Effect<InsertManyResult, MongoError.MongoError | ParseResult.ParseError, R> => {
|
|
121
|
+
const encode = Schema.encode(collection.schema)
|
|
122
|
+
return F.pipe(
|
|
123
|
+
docs,
|
|
124
|
+
Effect.forEach((doc) => encode(doc)),
|
|
125
|
+
Effect.flatMap((docs) => Effect.promise(() => collection.collection.insertMany(docs, options))),
|
|
126
|
+
Effect.catchAllDefect(MongoError.mongoErrorDie<InsertManyResult>("insertMany error"))
|
|
127
|
+
)
|
|
128
|
+
})
|
|
129
|
+
|
|
130
|
+
const isCollection = (x: unknown) => x instanceof Collection
|
package/src/Db.ts
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @since 0.0.1
|
|
3
|
+
*/
|
|
4
|
+
import type * as Schema from "@effect/schema/Schema"
|
|
5
|
+
import type * as Brand from "effect/Brand"
|
|
6
|
+
import * as Context from "effect/Context"
|
|
7
|
+
import * as Effect from "effect/Effect"
|
|
8
|
+
import * as F from "effect/Function"
|
|
9
|
+
import * as Layer from "effect/Layer"
|
|
10
|
+
import type { Document } from "mongodb"
|
|
11
|
+
import { Db } from "mongodb"
|
|
12
|
+
import type * as Collection from "./Collection.js"
|
|
13
|
+
import * as DocumentCollection from "./DocumentCollection.js"
|
|
14
|
+
import * as MongoClient from "./MongoClient.js"
|
|
15
|
+
import type * as MongoError from "./MongoError.js"
|
|
16
|
+
|
|
17
|
+
export const documentCollection: {
|
|
18
|
+
(name: string): (db: Db) => DocumentCollection.DocumentCollection
|
|
19
|
+
(db: Db, name: string): DocumentCollection.DocumentCollection
|
|
20
|
+
} = F.dual(
|
|
21
|
+
(args) => isDb(args[0]),
|
|
22
|
+
(db: Db, name: string): DocumentCollection.DocumentCollection =>
|
|
23
|
+
new DocumentCollection.DocumentCollection({
|
|
24
|
+
collection: db.collection(name)
|
|
25
|
+
})
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
export const collection: {
|
|
29
|
+
<A extends Document, I extends Document = A, R = never>(
|
|
30
|
+
name: string,
|
|
31
|
+
schema: Schema.Schema<A, I, R>
|
|
32
|
+
): (db: Db) => Collection.Collection<A, I, R>
|
|
33
|
+
<A extends Document, I extends Document = A, R = never>(
|
|
34
|
+
db: Db,
|
|
35
|
+
name: string,
|
|
36
|
+
schema: Schema.Schema<A, I, R>
|
|
37
|
+
): Collection.Collection<A, I, R>
|
|
38
|
+
} = F.dual(
|
|
39
|
+
(args) => isDb(args[0]),
|
|
40
|
+
<A extends Document, I extends Document = A, R = never>(
|
|
41
|
+
db: Db,
|
|
42
|
+
name: string,
|
|
43
|
+
schema: Schema.Schema<A, I, R>
|
|
44
|
+
): Collection.Collection<A, I, R> => DocumentCollection.typed(documentCollection(db, name), schema)
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
const isDb = (x: unknown) => x instanceof Db
|
|
48
|
+
|
|
49
|
+
export type DbService<K extends string> = {
|
|
50
|
+
db: Effect.Effect<Db, MongoError.MongoError>
|
|
51
|
+
} & Brand.Brand<K>
|
|
52
|
+
|
|
53
|
+
export const Tag = <K extends string>(key: K) => Context.GenericTag<DbService<K>>(key)
|
|
54
|
+
export type TagType<K extends string> = ReturnType<typeof Tag<K>>
|
|
55
|
+
|
|
56
|
+
export const fromEffect = <DbK extends string, MongoClientK extends string, E = never, R = never>(
|
|
57
|
+
dbTag: TagType<DbK>,
|
|
58
|
+
clientTag: MongoClient.TagType<MongoClientK>,
|
|
59
|
+
dbName: Effect.Effect<string, E, R>
|
|
60
|
+
) =>
|
|
61
|
+
Layer.effect(
|
|
62
|
+
dbTag,
|
|
63
|
+
Effect.gen(function*(_) {
|
|
64
|
+
const { client } = yield* _(clientTag)
|
|
65
|
+
const dbName_ = yield* _(dbName)
|
|
66
|
+
const db = yield* _(
|
|
67
|
+
client,
|
|
68
|
+
Effect.map((client) => MongoClient.db(client, dbName_)),
|
|
69
|
+
Effect.cached
|
|
70
|
+
)
|
|
71
|
+
return dbTag.of({ db } as DbService<DbK>) // TODO fix cast using branded ctor
|
|
72
|
+
})
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
export const fromConst = <DbK extends string, MongoClientK extends string>(
|
|
76
|
+
dbTag: TagType<DbK>,
|
|
77
|
+
clientTag: MongoClient.TagType<MongoClientK>,
|
|
78
|
+
dbName: string
|
|
79
|
+
) => fromEffect(dbTag, clientTag, Effect.succeed(dbName))
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @since 0.0.1
|
|
3
|
+
*/
|
|
4
|
+
import type * as Schema from "@effect/schema/Schema"
|
|
5
|
+
import * as Data from "effect/Data"
|
|
6
|
+
import * as Effect from "effect/Effect"
|
|
7
|
+
import * as F from "effect/Function"
|
|
8
|
+
import * as O from "effect/Option"
|
|
9
|
+
import type {
|
|
10
|
+
BulkWriteOptions,
|
|
11
|
+
Collection as MongoCollection,
|
|
12
|
+
Document,
|
|
13
|
+
Filter,
|
|
14
|
+
FindOptions,
|
|
15
|
+
InsertManyResult,
|
|
16
|
+
InsertOneOptions,
|
|
17
|
+
InsertOneResult,
|
|
18
|
+
OptionalUnlessRequiredId
|
|
19
|
+
} from "mongodb"
|
|
20
|
+
import * as Collection from "./Collection.js"
|
|
21
|
+
import * as DocumentFindCursor from "./DocumentFindCursor.js"
|
|
22
|
+
import * as MongoError from "./MongoError.js"
|
|
23
|
+
|
|
24
|
+
export class DocumentCollection extends Data.TaggedClass("DocumentCollection")<{
|
|
25
|
+
collection: MongoCollection
|
|
26
|
+
}> {
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export const find: {
|
|
30
|
+
(options?: FindOptions): (collection: DocumentCollection) => DocumentFindCursor.DocumentFindCursor
|
|
31
|
+
(
|
|
32
|
+
collection: DocumentCollection,
|
|
33
|
+
options?: FindOptions
|
|
34
|
+
): DocumentFindCursor.DocumentFindCursor
|
|
35
|
+
} = F.dual(
|
|
36
|
+
(args) => isDocumentCollection(args[0]),
|
|
37
|
+
(collection: DocumentCollection, options?: FindOptions) =>
|
|
38
|
+
new DocumentFindCursor.DocumentFindCursor(
|
|
39
|
+
{
|
|
40
|
+
cursor: collection.collection.find({}, options)
|
|
41
|
+
}
|
|
42
|
+
)
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
export const findOne: {
|
|
46
|
+
(
|
|
47
|
+
filter: Filter<Document>,
|
|
48
|
+
options?: FindOptions
|
|
49
|
+
): (
|
|
50
|
+
collection: DocumentCollection
|
|
51
|
+
) => Effect.Effect<O.Option<Document>, MongoError.MongoError>
|
|
52
|
+
(
|
|
53
|
+
collection: DocumentCollection,
|
|
54
|
+
filter: Filter<Document>,
|
|
55
|
+
options?: FindOptions
|
|
56
|
+
): Effect.Effect<O.Option<Document>, MongoError.MongoError>
|
|
57
|
+
} = F.dual(
|
|
58
|
+
(args) => isDocumentCollection(args[0]),
|
|
59
|
+
(
|
|
60
|
+
collection: DocumentCollection,
|
|
61
|
+
filter: Filter<Document>,
|
|
62
|
+
options?: FindOptions
|
|
63
|
+
): Effect.Effect<O.Option<Document>, MongoError.MongoError> =>
|
|
64
|
+
F.pipe(
|
|
65
|
+
Effect.promise(() => collection.collection.findOne(filter, options)),
|
|
66
|
+
Effect.map((value) => O.fromNullable(value)),
|
|
67
|
+
Effect.catchAllDefect(MongoError.mongoErrorDie<O.Option<Document>>("findOne error"))
|
|
68
|
+
)
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
export const insertOne: {
|
|
72
|
+
(
|
|
73
|
+
doc: OptionalUnlessRequiredId<Document>,
|
|
74
|
+
options?: InsertOneOptions
|
|
75
|
+
): (
|
|
76
|
+
collection: DocumentCollection
|
|
77
|
+
) => Effect.Effect<InsertOneResult, MongoError.MongoError>
|
|
78
|
+
(
|
|
79
|
+
collection: DocumentCollection,
|
|
80
|
+
doc: OptionalUnlessRequiredId<Document>,
|
|
81
|
+
options?: InsertOneOptions
|
|
82
|
+
): Effect.Effect<InsertOneResult, MongoError.MongoError>
|
|
83
|
+
} = F.dual((args) => isDocumentCollection(args[0]), (
|
|
84
|
+
collection: DocumentCollection,
|
|
85
|
+
doc: OptionalUnlessRequiredId<Document>,
|
|
86
|
+
options?: InsertOneOptions
|
|
87
|
+
): Effect.Effect<InsertOneResult, MongoError.MongoError> =>
|
|
88
|
+
F.pipe(
|
|
89
|
+
Effect.promise(() => collection.collection.insertOne(doc, options)),
|
|
90
|
+
Effect.catchAllDefect(MongoError.mongoErrorDie<InsertOneResult>("insertOne error"))
|
|
91
|
+
))
|
|
92
|
+
|
|
93
|
+
export const insertMany: {
|
|
94
|
+
(
|
|
95
|
+
docs: Array<OptionalUnlessRequiredId<Document>>,
|
|
96
|
+
options?: BulkWriteOptions
|
|
97
|
+
): (
|
|
98
|
+
collection: DocumentCollection
|
|
99
|
+
) => Effect.Effect<InsertOneResult, MongoError.MongoError>
|
|
100
|
+
(
|
|
101
|
+
collection: DocumentCollection,
|
|
102
|
+
docs: Array<OptionalUnlessRequiredId<Document>>,
|
|
103
|
+
options?: BulkWriteOptions
|
|
104
|
+
): Effect.Effect<InsertOneResult, MongoError.MongoError>
|
|
105
|
+
} = F.dual((args) => isDocumentCollection(args[0]), (
|
|
106
|
+
collection: DocumentCollection,
|
|
107
|
+
docs: Array<OptionalUnlessRequiredId<Document>>,
|
|
108
|
+
options?: BulkWriteOptions
|
|
109
|
+
): Effect.Effect<InsertManyResult, MongoError.MongoError> =>
|
|
110
|
+
F.pipe(
|
|
111
|
+
Effect.promise(() => collection.collection.insertMany(docs, options)),
|
|
112
|
+
Effect.catchAllDefect(MongoError.mongoErrorDie<InsertManyResult>("insertMany error"))
|
|
113
|
+
))
|
|
114
|
+
|
|
115
|
+
export const typed: {
|
|
116
|
+
<A extends Document, I extends Document = A, R = never>(
|
|
117
|
+
schema: Schema.Schema<A, I, R>
|
|
118
|
+
): (collection: DocumentCollection) => Collection.Collection<A, I, R>
|
|
119
|
+
<A extends Document, I extends Document = A, R = never>(
|
|
120
|
+
collection: DocumentCollection,
|
|
121
|
+
schema: Schema.Schema<A, I, R>
|
|
122
|
+
): Collection.Collection<A, I, R>
|
|
123
|
+
} = F.dual((args) => isDocumentCollection(args[0]), <A extends Document, I extends Document = A, R = never>(
|
|
124
|
+
collection: DocumentCollection,
|
|
125
|
+
schema: Schema.Schema<A, I, R>
|
|
126
|
+
): Collection.Collection<A, I, R> => new Collection.Collection<A, I, R>({ collection: collection.collection, schema }))
|
|
127
|
+
|
|
128
|
+
const isDocumentCollection = (x: unknown) => x instanceof DocumentCollection
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @since 0.0.1
|
|
3
|
+
*/
|
|
4
|
+
import type * as Schema from "@effect/schema/Schema"
|
|
5
|
+
import * as Data from "effect/Data"
|
|
6
|
+
import * as Effect from "effect/Effect"
|
|
7
|
+
import * as F from "effect/Function"
|
|
8
|
+
import * as Stream from "effect/Stream"
|
|
9
|
+
import type { Document, FindCursor as MongoFindCursor, Sort, SortDirection } from "mongodb"
|
|
10
|
+
import * as FindCursor from "./FindCursor.js"
|
|
11
|
+
import * as MongoError from "./MongoError.js"
|
|
12
|
+
|
|
13
|
+
export class DocumentFindCursor extends Data.TaggedClass("DocumentFindCursor")<{
|
|
14
|
+
cursor: MongoFindCursor<Document>
|
|
15
|
+
}> {
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export const filter: {
|
|
19
|
+
(
|
|
20
|
+
filter: Document
|
|
21
|
+
): (cursor: DocumentFindCursor) => DocumentFindCursor
|
|
22
|
+
(cursor: DocumentFindCursor, filter: Document): DocumentFindCursor
|
|
23
|
+
} = F.dual(
|
|
24
|
+
(args) => isDocumentFindCursor(args[0]),
|
|
25
|
+
(cursor: DocumentFindCursor, filter: Document): DocumentFindCursor =>
|
|
26
|
+
new DocumentFindCursor({ cursor: cursor.cursor.filter(filter) })
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
export const project: {
|
|
30
|
+
(
|
|
31
|
+
value: Document
|
|
32
|
+
): (cursor: DocumentFindCursor) => DocumentFindCursor
|
|
33
|
+
(cursor: DocumentFindCursor, value: Document): DocumentFindCursor
|
|
34
|
+
} = F.dual(
|
|
35
|
+
(args) => isDocumentFindCursor(args[0]),
|
|
36
|
+
(cursor: DocumentFindCursor, value: Document): DocumentFindCursor =>
|
|
37
|
+
new DocumentFindCursor({ cursor: cursor.cursor.project(value) })
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
export const sort: {
|
|
41
|
+
(
|
|
42
|
+
sort: Sort | string,
|
|
43
|
+
direction?: SortDirection
|
|
44
|
+
): (cursor: DocumentFindCursor) => DocumentFindCursor
|
|
45
|
+
(cursor: DocumentFindCursor, sort: Sort | string, direction?: SortDirection): DocumentFindCursor
|
|
46
|
+
} = F.dual(
|
|
47
|
+
(args) => isDocumentFindCursor(args[0]),
|
|
48
|
+
(cursor: DocumentFindCursor, sort: Sort | string, direction?: SortDirection): DocumentFindCursor =>
|
|
49
|
+
new DocumentFindCursor({ cursor: cursor.cursor.sort(sort, direction) })
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
export const limit: {
|
|
53
|
+
(
|
|
54
|
+
value: number
|
|
55
|
+
): (cursor: DocumentFindCursor) => DocumentFindCursor
|
|
56
|
+
(cursor: DocumentFindCursor, value: number): DocumentFindCursor
|
|
57
|
+
} = F.dual(
|
|
58
|
+
(args) => isDocumentFindCursor(args[0]),
|
|
59
|
+
(cursor: DocumentFindCursor, value: number): DocumentFindCursor =>
|
|
60
|
+
new DocumentFindCursor({ cursor: cursor.cursor.limit(value) })
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
export const toArray = (cursor: DocumentFindCursor): Effect.Effect<ReadonlyArray<Document>, MongoError.MongoError> =>
|
|
64
|
+
F.pipe(
|
|
65
|
+
Effect.tryPromise({ try: () => cursor.cursor.toArray(), catch: F.identity }),
|
|
66
|
+
Effect.catchAll(MongoError.mongoErrorDie<ReadonlyArray<Document>>("toArray error"))
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
export const toStream = (
|
|
70
|
+
cursor: DocumentFindCursor
|
|
71
|
+
): Stream.Stream<Document, MongoError.MongoError> =>
|
|
72
|
+
F.pipe(
|
|
73
|
+
Stream.fromAsyncIterable(cursor.cursor, F.identity),
|
|
74
|
+
Stream.catchAll(MongoError.mongoErrorStream<Document>("Unable to read from mongodb cursor"))
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
export const typed: {
|
|
78
|
+
<A, I = A, R = never>(
|
|
79
|
+
schema: Schema.Schema<A, I, R>
|
|
80
|
+
): (cursor: DocumentFindCursor) => FindCursor.FindCursor<A, I, R>
|
|
81
|
+
<A, I = A, R = never>(
|
|
82
|
+
cursor: DocumentFindCursor,
|
|
83
|
+
schema: Schema.Schema<A, I, R>
|
|
84
|
+
): FindCursor.FindCursor<A, I, R>
|
|
85
|
+
} = F.dual((args) => isDocumentFindCursor(args[0]), <A, I = A, R = never>(
|
|
86
|
+
cursor: DocumentFindCursor,
|
|
87
|
+
schema: Schema.Schema<A, I, R>
|
|
88
|
+
): FindCursor.FindCursor<A, I, R> => new FindCursor.FindCursor<A, I, R>({ cursor: cursor.cursor, schema }))
|
|
89
|
+
|
|
90
|
+
const isDocumentFindCursor = (x: unknown) => x instanceof DocumentFindCursor
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @since 0.0.1
|
|
3
|
+
*/
|
|
4
|
+
import type * as ParseResult from "@effect/schema/ParseResult"
|
|
5
|
+
import * as Schema from "@effect/schema/Schema"
|
|
6
|
+
import * as Data from "effect/Data"
|
|
7
|
+
import * as Effect from "effect/Effect"
|
|
8
|
+
import * as F from "effect/Function"
|
|
9
|
+
import * as Stream from "effect/Stream"
|
|
10
|
+
import * as Tuple from "effect/Tuple"
|
|
11
|
+
import type { Document, FindCursor as FindCursor_, Sort, SortDirection } from "mongodb"
|
|
12
|
+
import * as MongoError from "./MongoError.js"
|
|
13
|
+
|
|
14
|
+
import type * as E from "effect/Either"
|
|
15
|
+
|
|
16
|
+
export class FindCursor<A, I = A, R = never> extends Data.TaggedClass("FindCursor")<{
|
|
17
|
+
cursor: FindCursor_<unknown>
|
|
18
|
+
schema: Schema.Schema<A, I, R>
|
|
19
|
+
}> {}
|
|
20
|
+
|
|
21
|
+
export const filter: {
|
|
22
|
+
<T extends Document = Document>(
|
|
23
|
+
filter: T
|
|
24
|
+
): <A, I = A, R = never>(cursor: FindCursor<A, I, R>) => FindCursor<A, I, R>
|
|
25
|
+
<A, I = A, R = never, T extends Document = Document>(
|
|
26
|
+
cursor: FindCursor<A, I, R>,
|
|
27
|
+
filter: T
|
|
28
|
+
): FindCursor<A, I, R>
|
|
29
|
+
} = F.dual(
|
|
30
|
+
(args) => isFindCursor(args[0]),
|
|
31
|
+
<A, I = A, R = never, T extends Document = Document>(
|
|
32
|
+
cursor: FindCursor<A, I, R>,
|
|
33
|
+
filter: T
|
|
34
|
+
): FindCursor<A, I, R> => new FindCursor({ cursor: cursor.cursor.filter(filter), schema: cursor.schema })
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
export const project: {
|
|
38
|
+
<B, BI = B, BR = never, T extends Document = Document>(
|
|
39
|
+
newSchema: Schema.Schema<B, BI, BR>,
|
|
40
|
+
value: T
|
|
41
|
+
): <A, I = A, R = never>(cursor: FindCursor<A, I, R>) => FindCursor<B, BI, BR>
|
|
42
|
+
<A, B, I = A, R = never, BI = B, BR = never, T extends Document = Document>(
|
|
43
|
+
cursor: FindCursor<A, I, R>,
|
|
44
|
+
newSchema: Schema.Schema<B, BI, BR>,
|
|
45
|
+
value: T
|
|
46
|
+
): FindCursor<B, BI, BR>
|
|
47
|
+
} = F.dual(
|
|
48
|
+
(args) => isFindCursor(args[0]),
|
|
49
|
+
<A, B, I = A, R = never, BI = B, BR = never, T extends Document = Document>(
|
|
50
|
+
cursor: FindCursor<A, I, R>,
|
|
51
|
+
newSchema: Schema.Schema<B, BI, BR>,
|
|
52
|
+
value: T
|
|
53
|
+
): FindCursor<B, BI, BR> => new FindCursor({ cursor: cursor.cursor.project(value), schema: newSchema })
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
export const sort: {
|
|
57
|
+
(
|
|
58
|
+
sort: Sort | string,
|
|
59
|
+
direction?: SortDirection
|
|
60
|
+
): <A, I = A, R = never>(cursor: FindCursor<A, I, R>) => FindCursor<A, I, R>
|
|
61
|
+
<A, I = A, R = never>(
|
|
62
|
+
cursor: FindCursor<A, I, R>,
|
|
63
|
+
sort: Sort | string,
|
|
64
|
+
direction?: SortDirection
|
|
65
|
+
): FindCursor<A, I, R>
|
|
66
|
+
} = F.dual(
|
|
67
|
+
(args) => isFindCursor(args[0]),
|
|
68
|
+
<A, I = A, R = never>(
|
|
69
|
+
cursor: FindCursor<A, I, R>,
|
|
70
|
+
sort: Sort | string,
|
|
71
|
+
direction?: SortDirection
|
|
72
|
+
): FindCursor<A, I, R> => new FindCursor({ cursor: cursor.cursor.sort(sort, direction), schema: cursor.schema })
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
export const limit: {
|
|
76
|
+
(
|
|
77
|
+
value: number
|
|
78
|
+
): <A, I = A, R = never>(cursor: FindCursor<A, I, R>) => FindCursor<A, I, R>
|
|
79
|
+
<A, I = A, R = never>(cursor: FindCursor<A, I, R>, value: number): FindCursor<A, I, R>
|
|
80
|
+
} = F.dual(
|
|
81
|
+
(args) => isFindCursor(args[0]),
|
|
82
|
+
<A, I = A, R = never>(cursor: FindCursor<A, I, R>, value: number): FindCursor<A, I, R> =>
|
|
83
|
+
new FindCursor({ cursor: cursor.cursor.limit(value), schema: cursor.schema })
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
export const toArray = <A, I = A, R = never>(cursor: FindCursor<A, I, R>) => {
|
|
87
|
+
const decode = Schema.decodeUnknown(cursor.schema)
|
|
88
|
+
return Effect.tryPromise({ try: () => cursor.cursor.toArray(), catch: F.identity }).pipe(
|
|
89
|
+
Effect.catchAll(MongoError.mongoErrorDie<ReadonlyArray<A>>("Unable to get array from mongodb cursor")),
|
|
90
|
+
Effect.flatMap(Effect.forEach((x) => decode(x)))
|
|
91
|
+
)
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export const toArrayEither = <A, I = A, R = never>(cursor: FindCursor<A, I, R>) => {
|
|
95
|
+
const decode = Schema.decodeUnknown(cursor.schema)
|
|
96
|
+
return Effect.tryPromise({ try: () => cursor.cursor.toArray(), catch: F.identity }).pipe(
|
|
97
|
+
Effect.catchAll(MongoError.mongoErrorDie<ReadonlyArray<A>>("Unable to get array from mongodb cursor")),
|
|
98
|
+
Effect.flatMap(Effect.forEach((x) =>
|
|
99
|
+
F.pipe(
|
|
100
|
+
// keep new line
|
|
101
|
+
decode(x),
|
|
102
|
+
Effect.mapError((error) => Tuple.make(x, error)),
|
|
103
|
+
Effect.either
|
|
104
|
+
)
|
|
105
|
+
))
|
|
106
|
+
)
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export const toStream = <A, I = A, R = never>(
|
|
110
|
+
cursor: FindCursor<A, I, R>
|
|
111
|
+
): Stream.Stream<A, MongoError.MongoError | ParseResult.ParseError, R> => {
|
|
112
|
+
const decode = Schema.decodeUnknown(cursor.schema)
|
|
113
|
+
return F.pipe(
|
|
114
|
+
Stream.fromAsyncIterable(cursor.cursor, F.identity),
|
|
115
|
+
Stream.catchAll(MongoError.mongoErrorStream<A>("Unable to get stream from mongodb cursor")),
|
|
116
|
+
Stream.mapEffect((x) => decode(x))
|
|
117
|
+
)
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export const toStreamEither = <A, I = A, R = never>(
|
|
121
|
+
cursor: FindCursor<A, I, R>
|
|
122
|
+
): Stream.Stream<E.Either<A, [document: unknown, error: ParseResult.ParseError]>, MongoError.MongoError, R> => {
|
|
123
|
+
const decode = Schema.decodeUnknown(cursor.schema)
|
|
124
|
+
return F.pipe(
|
|
125
|
+
Stream.fromAsyncIterable(cursor.cursor, F.identity),
|
|
126
|
+
Stream.catchAll(MongoError.mongoErrorStream<A>("Unable to get stream either from mongodb cursor")),
|
|
127
|
+
Stream.mapEffect((x) =>
|
|
128
|
+
F.pipe(
|
|
129
|
+
// keep new line
|
|
130
|
+
decode(x),
|
|
131
|
+
Effect.mapError((error) => Tuple.make(x, error)),
|
|
132
|
+
Effect.either
|
|
133
|
+
)
|
|
134
|
+
)
|
|
135
|
+
)
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const isFindCursor = (x: unknown): x is FindCursor<unknown> => x instanceof FindCursor
|