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.
Files changed (74) hide show
  1. package/Collection/package.json +6 -0
  2. package/Db/package.json +6 -0
  3. package/DocumentCollection/package.json +6 -0
  4. package/DocumentFindCursor/package.json +6 -0
  5. package/FindCursor/package.json +6 -0
  6. package/LICENSE +21 -0
  7. package/MongoClient/package.json +6 -0
  8. package/MongoError/package.json +6 -0
  9. package/README.md +28 -0
  10. package/dist/cjs/Collection.js +33 -0
  11. package/dist/cjs/Collection.js.map +1 -0
  12. package/dist/cjs/Db.js +36 -0
  13. package/dist/cjs/Db.js.map +1 -0
  14. package/dist/cjs/DocumentCollection.js +29 -0
  15. package/dist/cjs/DocumentCollection.js.map +1 -0
  16. package/dist/cjs/DocumentFindCursor.js +41 -0
  17. package/dist/cjs/DocumentFindCursor.js.map +1 -0
  18. package/dist/cjs/FindCursor.js +65 -0
  19. package/dist/cjs/FindCursor.js.map +1 -0
  20. package/dist/cjs/MongoClient.js +20 -0
  21. package/dist/cjs/MongoClient.js.map +1 -0
  22. package/dist/cjs/MongoError.js +33 -0
  23. package/dist/cjs/MongoError.js.map +1 -0
  24. package/dist/cjs/index.js +23 -0
  25. package/dist/cjs/index.js.map +1 -0
  26. package/dist/cjs/internal/version.js +14 -0
  27. package/dist/cjs/internal/version.js.map +1 -0
  28. package/dist/dts/Collection.d.ts +37 -0
  29. package/dist/dts/Collection.d.ts.map +1 -0
  30. package/dist/dts/Db.d.ts +30 -0
  31. package/dist/dts/Db.d.ts.map +1 -0
  32. package/dist/dts/DocumentCollection.d.ts +39 -0
  33. package/dist/dts/DocumentCollection.d.ts.map +1 -0
  34. package/dist/dts/DocumentFindCursor.d.ts +40 -0
  35. package/dist/dts/DocumentFindCursor.d.ts.map +1 -0
  36. package/dist/dts/FindCursor.d.ts +40 -0
  37. package/dist/dts/FindCursor.d.ts.map +1 -0
  38. package/dist/dts/MongoClient.d.ts +21 -0
  39. package/dist/dts/MongoClient.d.ts.map +1 -0
  40. package/dist/dts/MongoError.d.ts +21 -0
  41. package/dist/dts/MongoError.d.ts.map +1 -0
  42. package/dist/dts/index.d.ts +29 -0
  43. package/dist/dts/index.d.ts.map +1 -0
  44. package/dist/dts/internal/version.d.ts +3 -0
  45. package/dist/dts/internal/version.d.ts.map +1 -0
  46. package/dist/esm/Collection.js +24 -0
  47. package/dist/esm/Collection.js.map +1 -0
  48. package/dist/esm/Db.js +25 -0
  49. package/dist/esm/Db.js.map +1 -0
  50. package/dist/esm/DocumentCollection.js +20 -0
  51. package/dist/esm/DocumentCollection.js.map +1 -0
  52. package/dist/esm/DocumentFindCursor.js +30 -0
  53. package/dist/esm/DocumentFindCursor.js.map +1 -0
  54. package/dist/esm/FindCursor.js +52 -0
  55. package/dist/esm/FindCursor.js.map +1 -0
  56. package/dist/esm/MongoClient.js +10 -0
  57. package/dist/esm/MongoClient.js.map +1 -0
  58. package/dist/esm/MongoError.js +23 -0
  59. package/dist/esm/MongoError.js.map +1 -0
  60. package/dist/esm/index.js +29 -0
  61. package/dist/esm/index.js.map +1 -0
  62. package/dist/esm/internal/version.js +6 -0
  63. package/dist/esm/internal/version.js.map +1 -0
  64. package/dist/esm/package.json +4 -0
  65. package/package.json +93 -0
  66. package/src/Collection.ts +130 -0
  67. package/src/Db.ts +79 -0
  68. package/src/DocumentCollection.ts +128 -0
  69. package/src/DocumentFindCursor.ts +90 -0
  70. package/src/FindCursor.ts +138 -0
  71. package/src/MongoClient.ts +35 -0
  72. package/src/MongoError.ts +40 -0
  73. package/src/index.ts +34 -0
  74. 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