mongo.do 0.1.0 → 0.1.1
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/dist/cli/index.d.ts +1 -15
- package/dist/cli/index.js +4083 -196
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.ts +2740 -20
- package/dist/index.js +9375 -27
- package/dist/index.js.map +1 -1
- package/dist/worker-entrypoint-BEW23Gmp.d.ts +1331 -0
- package/dist/worker.d.ts +6 -5
- package/dist/worker.js +5477 -18
- package/dist/worker.js.map +1 -1
- package/package.json +3 -2
- package/dist/agentfs/adapters/anthropic.d.ts +0 -176
- package/dist/agentfs/adapters/anthropic.d.ts.map +0 -1
- package/dist/agentfs/adapters/anthropic.js +0 -629
- package/dist/agentfs/adapters/anthropic.js.map +0 -1
- package/dist/agentfs/adapters/index.d.ts +0 -21
- package/dist/agentfs/adapters/index.d.ts.map +0 -1
- package/dist/agentfs/adapters/index.js +0 -23
- package/dist/agentfs/adapters/index.js.map +0 -1
- package/dist/agentfs/adapters/vercel.d.ts +0 -260
- package/dist/agentfs/adapters/vercel.d.ts.map +0 -1
- package/dist/agentfs/adapters/vercel.js +0 -288
- package/dist/agentfs/adapters/vercel.js.map +0 -1
- package/dist/agentfs/glob.d.ts +0 -116
- package/dist/agentfs/glob.d.ts.map +0 -1
- package/dist/agentfs/glob.js +0 -270
- package/dist/agentfs/glob.js.map +0 -1
- package/dist/agentfs/grep.d.ts +0 -83
- package/dist/agentfs/grep.d.ts.map +0 -1
- package/dist/agentfs/grep.js +0 -193
- package/dist/agentfs/grep.js.map +0 -1
- package/dist/agentfs/index.d.ts +0 -22
- package/dist/agentfs/index.d.ts.map +0 -1
- package/dist/agentfs/index.js +0 -18
- package/dist/agentfs/index.js.map +0 -1
- package/dist/agentfs/kv-store.d.ts +0 -128
- package/dist/agentfs/kv-store.d.ts.map +0 -1
- package/dist/agentfs/kv-store.js +0 -227
- package/dist/agentfs/kv-store.js.map +0 -1
- package/dist/agentfs/mondo-agent.d.ts +0 -255
- package/dist/agentfs/mondo-agent.d.ts.map +0 -1
- package/dist/agentfs/mondo-agent.js +0 -879
- package/dist/agentfs/mondo-agent.js.map +0 -1
- package/dist/agentfs/toolcalls.d.ts +0 -130
- package/dist/agentfs/toolcalls.d.ts.map +0 -1
- package/dist/agentfs/toolcalls.js +0 -178
- package/dist/agentfs/toolcalls.js.map +0 -1
- package/dist/agentfs/types.d.ts +0 -171
- package/dist/agentfs/types.d.ts.map +0 -1
- package/dist/agentfs/types.js +0 -7
- package/dist/agentfs/types.js.map +0 -1
- package/dist/agentfs/vfs.d.ts +0 -249
- package/dist/agentfs/vfs.d.ts.map +0 -1
- package/dist/agentfs/vfs.js +0 -469
- package/dist/agentfs/vfs.js.map +0 -1
- package/dist/cli/index.d.ts.map +0 -1
- package/dist/cli/mcp.d.ts +0 -119
- package/dist/cli/mcp.d.ts.map +0 -1
- package/dist/cli/mcp.js +0 -418
- package/dist/cli/mcp.js.map +0 -1
- package/dist/cli/server.d.ts +0 -179
- package/dist/cli/server.d.ts.map +0 -1
- package/dist/cli/server.js +0 -441
- package/dist/cli/server.js.map +0 -1
- package/dist/client/Collection.d.ts +0 -199
- package/dist/client/Collection.d.ts.map +0 -1
- package/dist/client/Collection.js +0 -256
- package/dist/client/Collection.js.map +0 -1
- package/dist/client/Database.d.ts +0 -68
- package/dist/client/Database.d.ts.map +0 -1
- package/dist/client/Database.js +0 -105
- package/dist/client/Database.js.map +0 -1
- package/dist/client/MongoClient.d.ts +0 -165
- package/dist/client/MongoClient.d.ts.map +0 -1
- package/dist/client/MongoClient.js +0 -307
- package/dist/client/MongoClient.js.map +0 -1
- package/dist/client/aggregation-cursor.d.ts +0 -210
- package/dist/client/aggregation-cursor.d.ts.map +0 -1
- package/dist/client/aggregation-cursor.js +0 -509
- package/dist/client/aggregation-cursor.js.map +0 -1
- package/dist/client/bulk-write.d.ts +0 -216
- package/dist/client/bulk-write.d.ts.map +0 -1
- package/dist/client/bulk-write.js +0 -63
- package/dist/client/bulk-write.js.map +0 -1
- package/dist/client/change-stream.d.ts +0 -245
- package/dist/client/change-stream.d.ts.map +0 -1
- package/dist/client/change-stream.js +0 -429
- package/dist/client/change-stream.js.map +0 -1
- package/dist/client/cursor.d.ts +0 -85
- package/dist/client/cursor.d.ts.map +0 -1
- package/dist/client/cursor.js +0 -156
- package/dist/client/cursor.js.map +0 -1
- package/dist/client/http-cursor.d.ts +0 -233
- package/dist/client/http-cursor.d.ts.map +0 -1
- package/dist/client/http-cursor.js +0 -496
- package/dist/client/http-cursor.js.map +0 -1
- package/dist/client/index.d.ts +0 -18
- package/dist/client/index.d.ts.map +0 -1
- package/dist/client/index.js +0 -24
- package/dist/client/index.js.map +0 -1
- package/dist/client/mongo-client.d.ts +0 -60
- package/dist/client/mongo-client.d.ts.map +0 -1
- package/dist/client/mongo-client.js +0 -190
- package/dist/client/mongo-client.js.map +0 -1
- package/dist/client/mongo-collection.d.ts +0 -359
- package/dist/client/mongo-collection.d.ts.map +0 -1
- package/dist/client/mongo-collection.js +0 -1641
- package/dist/client/mongo-collection.js.map +0 -1
- package/dist/client/mongo-cursor.d.ts +0 -257
- package/dist/client/mongo-cursor.d.ts.map +0 -1
- package/dist/client/mongo-cursor.js +0 -621
- package/dist/client/mongo-cursor.js.map +0 -1
- package/dist/client/mongo-database.d.ts +0 -88
- package/dist/client/mongo-database.d.ts.map +0 -1
- package/dist/client/mongo-database.js +0 -139
- package/dist/client/mongo-database.js.map +0 -1
- package/dist/client/session.d.ts +0 -210
- package/dist/client/session.d.ts.map +0 -1
- package/dist/client/session.js +0 -326
- package/dist/client/session.js.map +0 -1
- package/dist/durable-object/index-manager.d.ts +0 -173
- package/dist/durable-object/index-manager.d.ts.map +0 -1
- package/dist/durable-object/index-manager.js +0 -764
- package/dist/durable-object/index-manager.js.map +0 -1
- package/dist/durable-object/index.d.ts +0 -12
- package/dist/durable-object/index.d.ts.map +0 -1
- package/dist/durable-object/index.js +0 -8
- package/dist/durable-object/index.js.map +0 -1
- package/dist/durable-object/mcp-handler.d.ts +0 -52
- package/dist/durable-object/mcp-handler.d.ts.map +0 -1
- package/dist/durable-object/mcp-handler.js +0 -186
- package/dist/durable-object/mcp-handler.js.map +0 -1
- package/dist/durable-object/migrations.d.ts +0 -40
- package/dist/durable-object/migrations.d.ts.map +0 -1
- package/dist/durable-object/migrations.js +0 -121
- package/dist/durable-object/migrations.js.map +0 -1
- package/dist/durable-object/mondo-database.d.ts +0 -148
- package/dist/durable-object/mondo-database.d.ts.map +0 -1
- package/dist/durable-object/mondo-database.js +0 -621
- package/dist/durable-object/mondo-database.js.map +0 -1
- package/dist/durable-object/schema.d.ts +0 -192
- package/dist/durable-object/schema.d.ts.map +0 -1
- package/dist/durable-object/schema.js +0 -186
- package/dist/durable-object/schema.js.map +0 -1
- package/dist/embedding/document-serializer.d.ts +0 -118
- package/dist/embedding/document-serializer.d.ts.map +0 -1
- package/dist/embedding/document-serializer.js +0 -339
- package/dist/embedding/document-serializer.js.map +0 -1
- package/dist/embedding/embedding-manager.d.ts +0 -136
- package/dist/embedding/embedding-manager.d.ts.map +0 -1
- package/dist/embedding/embedding-manager.js +0 -176
- package/dist/embedding/embedding-manager.js.map +0 -1
- package/dist/embedding/index.d.ts +0 -9
- package/dist/embedding/index.d.ts.map +0 -1
- package/dist/embedding/index.js +0 -9
- package/dist/embedding/index.js.map +0 -1
- package/dist/executor/aggregation-executor.d.ts +0 -93
- package/dist/executor/aggregation-executor.d.ts.map +0 -1
- package/dist/executor/aggregation-executor.js +0 -275
- package/dist/executor/aggregation-executor.js.map +0 -1
- package/dist/executor/function-executor.d.ts +0 -39
- package/dist/executor/function-executor.d.ts.map +0 -1
- package/dist/executor/function-executor.js +0 -168
- package/dist/executor/function-executor.js.map +0 -1
- package/dist/executor/index.d.ts +0 -4
- package/dist/executor/index.d.ts.map +0 -1
- package/dist/executor/index.js +0 -4
- package/dist/executor/index.js.map +0 -1
- package/dist/executor/vector-search-executor.d.ts +0 -71
- package/dist/executor/vector-search-executor.d.ts.map +0 -1
- package/dist/executor/vector-search-executor.js +0 -113
- package/dist/executor/vector-search-executor.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/mcp/adapters/anthropic-adapter.d.ts +0 -256
- package/dist/mcp/adapters/anthropic-adapter.d.ts.map +0 -1
- package/dist/mcp/adapters/anthropic-adapter.js +0 -409
- package/dist/mcp/adapters/anthropic-adapter.js.map +0 -1
- package/dist/mcp/adapters/base-adapter.d.ts +0 -164
- package/dist/mcp/adapters/base-adapter.d.ts.map +0 -1
- package/dist/mcp/adapters/base-adapter.js +0 -277
- package/dist/mcp/adapters/base-adapter.js.map +0 -1
- package/dist/mcp/adapters/errors.d.ts +0 -173
- package/dist/mcp/adapters/errors.d.ts.map +0 -1
- package/dist/mcp/adapters/errors.js +0 -305
- package/dist/mcp/adapters/errors.js.map +0 -1
- package/dist/mcp/adapters/index.d.ts +0 -65
- package/dist/mcp/adapters/index.d.ts.map +0 -1
- package/dist/mcp/adapters/index.js +0 -92
- package/dist/mcp/adapters/index.js.map +0 -1
- package/dist/mcp/adapters/streaming.d.ts +0 -200
- package/dist/mcp/adapters/streaming.d.ts.map +0 -1
- package/dist/mcp/adapters/streaming.js +0 -381
- package/dist/mcp/adapters/streaming.js.map +0 -1
- package/dist/mcp/adapters/vercel-adapter.d.ts +0 -321
- package/dist/mcp/adapters/vercel-adapter.d.ts.map +0 -1
- package/dist/mcp/adapters/vercel-adapter.js +0 -487
- package/dist/mcp/adapters/vercel-adapter.js.map +0 -1
- package/dist/mcp/agent.d.ts +0 -192
- package/dist/mcp/agent.d.ts.map +0 -1
- package/dist/mcp/agent.js +0 -338
- package/dist/mcp/agent.js.map +0 -1
- package/dist/mcp/cli.d.ts +0 -71
- package/dist/mcp/cli.d.ts.map +0 -1
- package/dist/mcp/cli.js +0 -218
- package/dist/mcp/cli.js.map +0 -1
- package/dist/mcp/index.d.ts +0 -15
- package/dist/mcp/index.d.ts.map +0 -1
- package/dist/mcp/index.js +0 -20
- package/dist/mcp/index.js.map +0 -1
- package/dist/mcp/sandbox/database-proxy.d.ts +0 -118
- package/dist/mcp/sandbox/database-proxy.d.ts.map +0 -1
- package/dist/mcp/sandbox/database-proxy.js +0 -154
- package/dist/mcp/sandbox/database-proxy.js.map +0 -1
- package/dist/mcp/sandbox/index.d.ts +0 -8
- package/dist/mcp/sandbox/index.d.ts.map +0 -1
- package/dist/mcp/sandbox/index.js +0 -7
- package/dist/mcp/sandbox/index.js.map +0 -1
- package/dist/mcp/sandbox/miniflare-evaluator.d.ts +0 -72
- package/dist/mcp/sandbox/miniflare-evaluator.d.ts.map +0 -1
- package/dist/mcp/sandbox/miniflare-evaluator.js +0 -379
- package/dist/mcp/sandbox/miniflare-evaluator.js.map +0 -1
- package/dist/mcp/sandbox/template.d.ts +0 -48
- package/dist/mcp/sandbox/template.d.ts.map +0 -1
- package/dist/mcp/sandbox/template.js +0 -147
- package/dist/mcp/sandbox/template.js.map +0 -1
- package/dist/mcp/sandbox/worker-evaluator.d.ts +0 -160
- package/dist/mcp/sandbox/worker-evaluator.d.ts.map +0 -1
- package/dist/mcp/sandbox/worker-evaluator.js +0 -217
- package/dist/mcp/sandbox/worker-evaluator.js.map +0 -1
- package/dist/mcp/server.d.ts +0 -75
- package/dist/mcp/server.d.ts.map +0 -1
- package/dist/mcp/server.js +0 -278
- package/dist/mcp/server.js.map +0 -1
- package/dist/mcp/tool-call-auditor.d.ts +0 -188
- package/dist/mcp/tool-call-auditor.d.ts.map +0 -1
- package/dist/mcp/tool-call-auditor.js +0 -198
- package/dist/mcp/tool-call-auditor.js.map +0 -1
- package/dist/mcp/tools/do.d.ts +0 -51
- package/dist/mcp/tools/do.d.ts.map +0 -1
- package/dist/mcp/tools/do.js +0 -113
- package/dist/mcp/tools/do.js.map +0 -1
- package/dist/mcp/tools/fetch.d.ts +0 -43
- package/dist/mcp/tools/fetch.d.ts.map +0 -1
- package/dist/mcp/tools/fetch.js +0 -127
- package/dist/mcp/tools/fetch.js.map +0 -1
- package/dist/mcp/tools/index.d.ts +0 -9
- package/dist/mcp/tools/index.d.ts.map +0 -1
- package/dist/mcp/tools/index.js +0 -9
- package/dist/mcp/tools/index.js.map +0 -1
- package/dist/mcp/tools/search.d.ts +0 -60
- package/dist/mcp/tools/search.d.ts.map +0 -1
- package/dist/mcp/tools/search.js +0 -278
- package/dist/mcp/tools/search.js.map +0 -1
- package/dist/mcp/transport/http.d.ts +0 -144
- package/dist/mcp/transport/http.d.ts.map +0 -1
- package/dist/mcp/transport/http.js +0 -545
- package/dist/mcp/transport/http.js.map +0 -1
- package/dist/mcp/transport/index.d.ts +0 -10
- package/dist/mcp/transport/index.d.ts.map +0 -1
- package/dist/mcp/transport/index.js +0 -12
- package/dist/mcp/transport/index.js.map +0 -1
- package/dist/mcp/transport/stdio.d.ts +0 -132
- package/dist/mcp/transport/stdio.d.ts.map +0 -1
- package/dist/mcp/transport/stdio.js +0 -466
- package/dist/mcp/transport/stdio.js.map +0 -1
- package/dist/mcp/types.d.ts +0 -476
- package/dist/mcp/types.d.ts.map +0 -1
- package/dist/mcp/types.js +0 -178
- package/dist/mcp/types.js.map +0 -1
- package/dist/olap/cdc/cdc-buffer.d.ts +0 -92
- package/dist/olap/cdc/cdc-buffer.d.ts.map +0 -1
- package/dist/olap/cdc/cdc-buffer.js +0 -146
- package/dist/olap/cdc/cdc-buffer.js.map +0 -1
- package/dist/olap/cdc/cdc-emitter.d.ts +0 -118
- package/dist/olap/cdc/cdc-emitter.d.ts.map +0 -1
- package/dist/olap/cdc/cdc-emitter.js +0 -217
- package/dist/olap/cdc/cdc-emitter.js.map +0 -1
- package/dist/olap/cdc/cdc-schema.d.ts +0 -119
- package/dist/olap/cdc/cdc-schema.d.ts.map +0 -1
- package/dist/olap/cdc/cdc-schema.js +0 -253
- package/dist/olap/cdc/cdc-schema.js.map +0 -1
- package/dist/olap/cdc/index.d.ts +0 -10
- package/dist/olap/cdc/index.d.ts.map +0 -1
- package/dist/olap/cdc/index.js +0 -10
- package/dist/olap/cdc/index.js.map +0 -1
- package/dist/olap/clickhouse/iceberg.d.ts +0 -164
- package/dist/olap/clickhouse/iceberg.d.ts.map +0 -1
- package/dist/olap/clickhouse/iceberg.js +0 -138
- package/dist/olap/clickhouse/iceberg.js.map +0 -1
- package/dist/olap/clickhouse/index.d.ts +0 -14
- package/dist/olap/clickhouse/index.d.ts.map +0 -1
- package/dist/olap/clickhouse/index.js +0 -14
- package/dist/olap/clickhouse/index.js.map +0 -1
- package/dist/olap/clickhouse/mapper.d.ts +0 -170
- package/dist/olap/clickhouse/mapper.d.ts.map +0 -1
- package/dist/olap/clickhouse/mapper.js +0 -654
- package/dist/olap/clickhouse/mapper.js.map +0 -1
- package/dist/olap/clickhouse/olap-backend.d.ts +0 -181
- package/dist/olap/clickhouse/olap-backend.d.ts.map +0 -1
- package/dist/olap/clickhouse/olap-backend.js +0 -1083
- package/dist/olap/clickhouse/olap-backend.js.map +0 -1
- package/dist/olap/clickhouse/query-executor.d.ts +0 -163
- package/dist/olap/clickhouse/query-executor.d.ts.map +0 -1
- package/dist/olap/clickhouse/query-executor.js +0 -560
- package/dist/olap/clickhouse/query-executor.js.map +0 -1
- package/dist/olap/clickhouse/query.d.ts +0 -134
- package/dist/olap/clickhouse/query.d.ts.map +0 -1
- package/dist/olap/clickhouse/query.js +0 -512
- package/dist/olap/clickhouse/query.js.map +0 -1
- package/dist/olap/stage/index.d.ts +0 -6
- package/dist/olap/stage/index.d.ts.map +0 -1
- package/dist/olap/stage/index.js +0 -6
- package/dist/olap/stage/index.js.map +0 -1
- package/dist/olap/stage/parser.d.ts +0 -68
- package/dist/olap/stage/parser.d.ts.map +0 -1
- package/dist/olap/stage/parser.js +0 -293
- package/dist/olap/stage/parser.js.map +0 -1
- package/dist/olap/stage/router.d.ts +0 -94
- package/dist/olap/stage/router.d.ts.map +0 -1
- package/dist/olap/stage/router.js +0 -390
- package/dist/olap/stage/router.js.map +0 -1
- package/dist/rpc/endpoint.d.ts +0 -52
- package/dist/rpc/endpoint.d.ts.map +0 -1
- package/dist/rpc/endpoint.js +0 -734
- package/dist/rpc/endpoint.js.map +0 -1
- package/dist/rpc/index.d.ts +0 -34
- package/dist/rpc/index.d.ts.map +0 -1
- package/dist/rpc/index.js +0 -45
- package/dist/rpc/index.js.map +0 -1
- package/dist/rpc/rpc-client.d.ts +0 -275
- package/dist/rpc/rpc-client.d.ts.map +0 -1
- package/dist/rpc/rpc-client.js +0 -735
- package/dist/rpc/rpc-client.js.map +0 -1
- package/dist/rpc/rpc-target.d.ts +0 -220
- package/dist/rpc/rpc-target.d.ts.map +0 -1
- package/dist/rpc/rpc-target.js +0 -500
- package/dist/rpc/rpc-target.js.map +0 -1
- package/dist/rpc/worker-entrypoint.d.ts +0 -159
- package/dist/rpc/worker-entrypoint.d.ts.map +0 -1
- package/dist/rpc/worker-entrypoint.js +0 -212
- package/dist/rpc/worker-entrypoint.js.map +0 -1
- package/dist/server.d.ts +0 -18
- package/dist/server.d.ts.map +0 -1
- package/dist/server.js +0 -129
- package/dist/server.js.map +0 -1
- package/dist/studio/components/browser/CollectionItem.d.ts +0 -26
- package/dist/studio/components/browser/CollectionItem.d.ts.map +0 -1
- package/dist/studio/components/browser/CollectionItem.js +0 -143
- package/dist/studio/components/browser/CollectionItem.js.map +0 -1
- package/dist/studio/components/browser/CollectionTree.d.ts +0 -45
- package/dist/studio/components/browser/CollectionTree.d.ts.map +0 -1
- package/dist/studio/components/browser/CollectionTree.js +0 -207
- package/dist/studio/components/browser/CollectionTree.js.map +0 -1
- package/dist/studio/components/browser/ConnectedDatabaseBrowser.d.ts +0 -51
- package/dist/studio/components/browser/ConnectedDatabaseBrowser.d.ts.map +0 -1
- package/dist/studio/components/browser/ConnectedDatabaseBrowser.js +0 -185
- package/dist/studio/components/browser/ConnectedDatabaseBrowser.js.map +0 -1
- package/dist/studio/components/browser/DatabaseBrowser.d.ts +0 -46
- package/dist/studio/components/browser/DatabaseBrowser.d.ts.map +0 -1
- package/dist/studio/components/browser/DatabaseBrowser.js +0 -304
- package/dist/studio/components/browser/DatabaseBrowser.js.map +0 -1
- package/dist/studio/components/browser/__tests__/CollectionItem.test.d.ts +0 -5
- package/dist/studio/components/browser/__tests__/CollectionItem.test.d.ts.map +0 -1
- package/dist/studio/components/browser/__tests__/CollectionItem.test.js +0 -169
- package/dist/studio/components/browser/__tests__/CollectionItem.test.js.map +0 -1
- package/dist/studio/components/browser/__tests__/CollectionTree.test.d.ts +0 -5
- package/dist/studio/components/browser/__tests__/CollectionTree.test.d.ts.map +0 -1
- package/dist/studio/components/browser/__tests__/CollectionTree.test.js +0 -203
- package/dist/studio/components/browser/__tests__/CollectionTree.test.js.map +0 -1
- package/dist/studio/components/browser/__tests__/DatabaseBrowser.e2e.test.d.ts +0 -8
- package/dist/studio/components/browser/__tests__/DatabaseBrowser.e2e.test.d.ts.map +0 -1
- package/dist/studio/components/browser/__tests__/DatabaseBrowser.e2e.test.js +0 -522
- package/dist/studio/components/browser/__tests__/DatabaseBrowser.e2e.test.js.map +0 -1
- package/dist/studio/components/browser/__tests__/DatabaseBrowser.test.d.ts +0 -5
- package/dist/studio/components/browser/__tests__/DatabaseBrowser.test.d.ts.map +0 -1
- package/dist/studio/components/browser/__tests__/DatabaseBrowser.test.js +0 -518
- package/dist/studio/components/browser/__tests__/DatabaseBrowser.test.js.map +0 -1
- package/dist/studio/components/browser/__tests__/setup.d.ts +0 -5
- package/dist/studio/components/browser/__tests__/setup.d.ts.map +0 -1
- package/dist/studio/components/browser/__tests__/setup.js +0 -22
- package/dist/studio/components/browser/__tests__/setup.js.map +0 -1
- package/dist/studio/components/browser/index.d.ts +0 -15
- package/dist/studio/components/browser/index.d.ts.map +0 -1
- package/dist/studio/components/browser/index.js +0 -10
- package/dist/studio/components/browser/index.js.map +0 -1
- package/dist/studio/components/browser/types.d.ts +0 -33
- package/dist/studio/components/browser/types.d.ts.map +0 -1
- package/dist/studio/components/browser/types.js +0 -5
- package/dist/studio/components/browser/types.js.map +0 -1
- package/dist/studio/components/connection/ConnectionForm.d.ts +0 -59
- package/dist/studio/components/connection/ConnectionForm.d.ts.map +0 -1
- package/dist/studio/components/connection/ConnectionForm.js +0 -274
- package/dist/studio/components/connection/ConnectionForm.js.map +0 -1
- package/dist/studio/components/connection/ConnectionList.d.ts +0 -59
- package/dist/studio/components/connection/ConnectionList.d.ts.map +0 -1
- package/dist/studio/components/connection/ConnectionList.js +0 -286
- package/dist/studio/components/connection/ConnectionList.js.map +0 -1
- package/dist/studio/components/connection/ConnectionPanel.d.ts +0 -132
- package/dist/studio/components/connection/ConnectionPanel.d.ts.map +0 -1
- package/dist/studio/components/connection/ConnectionPanel.js +0 -293
- package/dist/studio/components/connection/ConnectionPanel.js.map +0 -1
- package/dist/studio/components/connection/__tests__/ConnectionPanel.test.d.ts +0 -8
- package/dist/studio/components/connection/__tests__/ConnectionPanel.test.d.ts.map +0 -1
- package/dist/studio/components/connection/__tests__/ConnectionPanel.test.js +0 -632
- package/dist/studio/components/connection/__tests__/ConnectionPanel.test.js.map +0 -1
- package/dist/studio/components/connection/__tests__/setup.d.ts +0 -5
- package/dist/studio/components/connection/__tests__/setup.d.ts.map +0 -1
- package/dist/studio/components/connection/__tests__/setup.js +0 -11
- package/dist/studio/components/connection/__tests__/setup.js.map +0 -1
- package/dist/studio/components/connection/index.d.ts +0 -10
- package/dist/studio/components/connection/index.d.ts.map +0 -1
- package/dist/studio/components/connection/index.js +0 -7
- package/dist/studio/components/connection/index.js.map +0 -1
- package/dist/studio/components/crud/DeleteDocumentDialog.d.ts +0 -91
- package/dist/studio/components/crud/DeleteDocumentDialog.d.ts.map +0 -1
- package/dist/studio/components/crud/DeleteDocumentDialog.js +0 -273
- package/dist/studio/components/crud/DeleteDocumentDialog.js.map +0 -1
- package/dist/studio/components/crud/DocumentEditor.d.ts +0 -32
- package/dist/studio/components/crud/DocumentEditor.d.ts.map +0 -1
- package/dist/studio/components/crud/DocumentEditor.js +0 -546
- package/dist/studio/components/crud/DocumentEditor.js.map +0 -1
- package/dist/studio/components/crud/InsertDocumentDialog.d.ts +0 -78
- package/dist/studio/components/crud/InsertDocumentDialog.d.ts.map +0 -1
- package/dist/studio/components/crud/InsertDocumentDialog.js +0 -323
- package/dist/studio/components/crud/InsertDocumentDialog.js.map +0 -1
- package/dist/studio/components/crud/__tests__/DeleteDocumentDialog.test.d.ts +0 -5
- package/dist/studio/components/crud/__tests__/DeleteDocumentDialog.test.d.ts.map +0 -1
- package/dist/studio/components/crud/__tests__/DeleteDocumentDialog.test.js +0 -298
- package/dist/studio/components/crud/__tests__/DeleteDocumentDialog.test.js.map +0 -1
- package/dist/studio/components/crud/__tests__/DocumentEditor.test.d.ts +0 -8
- package/dist/studio/components/crud/__tests__/DocumentEditor.test.d.ts.map +0 -1
- package/dist/studio/components/crud/__tests__/DocumentEditor.test.js +0 -368
- package/dist/studio/components/crud/__tests__/DocumentEditor.test.js.map +0 -1
- package/dist/studio/components/crud/__tests__/InsertDocumentDialog.test.d.ts +0 -2
- package/dist/studio/components/crud/__tests__/InsertDocumentDialog.test.d.ts.map +0 -1
- package/dist/studio/components/crud/__tests__/InsertDocumentDialog.test.js +0 -352
- package/dist/studio/components/crud/__tests__/InsertDocumentDialog.test.js.map +0 -1
- package/dist/studio/components/crud/__tests__/setup.d.ts +0 -5
- package/dist/studio/components/crud/__tests__/setup.d.ts.map +0 -1
- package/dist/studio/components/crud/__tests__/setup.js +0 -22
- package/dist/studio/components/crud/__tests__/setup.js.map +0 -1
- package/dist/studio/components/crud/index.d.ts +0 -12
- package/dist/studio/components/crud/index.d.ts.map +0 -1
- package/dist/studio/components/crud/index.js +0 -11
- package/dist/studio/components/crud/index.js.map +0 -1
- package/dist/studio/hooks/useConnection.d.ts +0 -127
- package/dist/studio/hooks/useConnection.d.ts.map +0 -1
- package/dist/studio/hooks/useConnection.js +0 -414
- package/dist/studio/hooks/useConnection.js.map +0 -1
- package/dist/studio/hooks/useDatabaseBrowser.d.ts +0 -107
- package/dist/studio/hooks/useDatabaseBrowser.d.ts.map +0 -1
- package/dist/studio/hooks/useDatabaseBrowser.js +0 -294
- package/dist/studio/hooks/useDatabaseBrowser.js.map +0 -1
- package/dist/studio/index.d.ts +0 -16
- package/dist/studio/index.d.ts.map +0 -1
- package/dist/studio/index.js +0 -14
- package/dist/studio/index.js.map +0 -1
- package/dist/studio/types/connection.d.ts +0 -266
- package/dist/studio/types/connection.d.ts.map +0 -1
- package/dist/studio/types/connection.js +0 -159
- package/dist/studio/types/connection.js.map +0 -1
- package/dist/studio/vitest.config.d.ts +0 -3
- package/dist/studio/vitest.config.d.ts.map +0 -1
- package/dist/studio/vitest.config.js +0 -33
- package/dist/studio/vitest.config.js.map +0 -1
- package/dist/translator/aggregation-translator.d.ts +0 -51
- package/dist/translator/aggregation-translator.d.ts.map +0 -1
- package/dist/translator/aggregation-translator.js +0 -324
- package/dist/translator/aggregation-translator.js.map +0 -1
- package/dist/translator/dialect.d.ts +0 -131
- package/dist/translator/dialect.d.ts.map +0 -1
- package/dist/translator/dialect.js +0 -276
- package/dist/translator/dialect.js.map +0 -1
- package/dist/translator/geo-translator.d.ts +0 -91
- package/dist/translator/geo-translator.d.ts.map +0 -1
- package/dist/translator/geo-translator.js +0 -587
- package/dist/translator/geo-translator.js.map +0 -1
- package/dist/translator/hybrid-translator.d.ts +0 -70
- package/dist/translator/hybrid-translator.d.ts.map +0 -1
- package/dist/translator/hybrid-translator.js +0 -193
- package/dist/translator/hybrid-translator.js.map +0 -1
- package/dist/translator/index.d.ts +0 -13
- package/dist/translator/index.d.ts.map +0 -1
- package/dist/translator/index.js +0 -11
- package/dist/translator/index.js.map +0 -1
- package/dist/translator/query-translator.d.ts +0 -211
- package/dist/translator/query-translator.d.ts.map +0 -1
- package/dist/translator/query-translator.js +0 -1276
- package/dist/translator/query-translator.js.map +0 -1
- package/dist/translator/search-highlight.d.ts +0 -83
- package/dist/translator/search-highlight.d.ts.map +0 -1
- package/dist/translator/search-highlight.js +0 -83
- package/dist/translator/search-highlight.js.map +0 -1
- package/dist/translator/search-translator.d.ts +0 -155
- package/dist/translator/search-translator.d.ts.map +0 -1
- package/dist/translator/search-translator.js +0 -241
- package/dist/translator/search-translator.js.map +0 -1
- package/dist/translator/stages/add-fields-stage.d.ts +0 -7
- package/dist/translator/stages/add-fields-stage.d.ts.map +0 -1
- package/dist/translator/stages/add-fields-stage.js +0 -72
- package/dist/translator/stages/add-fields-stage.js.map +0 -1
- package/dist/translator/stages/bucket-stage.d.ts +0 -7
- package/dist/translator/stages/bucket-stage.d.ts.map +0 -1
- package/dist/translator/stages/bucket-stage.js +0 -87
- package/dist/translator/stages/bucket-stage.js.map +0 -1
- package/dist/translator/stages/count-stage.d.ts +0 -7
- package/dist/translator/stages/count-stage.d.ts.map +0 -1
- package/dist/translator/stages/count-stage.js +0 -12
- package/dist/translator/stages/count-stage.js.map +0 -1
- package/dist/translator/stages/expression-translator.d.ts +0 -68
- package/dist/translator/stages/expression-translator.d.ts.map +0 -1
- package/dist/translator/stages/expression-translator.js +0 -467
- package/dist/translator/stages/expression-translator.js.map +0 -1
- package/dist/translator/stages/facet-stage.d.ts +0 -13
- package/dist/translator/stages/facet-stage.d.ts.map +0 -1
- package/dist/translator/stages/facet-stage.js +0 -26
- package/dist/translator/stages/facet-stage.js.map +0 -1
- package/dist/translator/stages/fusion-stages.d.ts +0 -118
- package/dist/translator/stages/fusion-stages.d.ts.map +0 -1
- package/dist/translator/stages/fusion-stages.js +0 -201
- package/dist/translator/stages/fusion-stages.js.map +0 -1
- package/dist/translator/stages/group-stage.d.ts +0 -8
- package/dist/translator/stages/group-stage.d.ts.map +0 -1
- package/dist/translator/stages/group-stage.js +0 -123
- package/dist/translator/stages/group-stage.js.map +0 -1
- package/dist/translator/stages/index.d.ts +0 -24
- package/dist/translator/stages/index.d.ts.map +0 -1
- package/dist/translator/stages/index.js +0 -24
- package/dist/translator/stages/index.js.map +0 -1
- package/dist/translator/stages/join-optimizer.d.ts +0 -37
- package/dist/translator/stages/join-optimizer.d.ts.map +0 -1
- package/dist/translator/stages/join-optimizer.js +0 -93
- package/dist/translator/stages/join-optimizer.js.map +0 -1
- package/dist/translator/stages/limit-stage.d.ts +0 -7
- package/dist/translator/stages/limit-stage.d.ts.map +0 -1
- package/dist/translator/stages/limit-stage.js +0 -11
- package/dist/translator/stages/limit-stage.js.map +0 -1
- package/dist/translator/stages/lookup-stage.d.ts +0 -7
- package/dist/translator/stages/lookup-stage.d.ts.map +0 -1
- package/dist/translator/stages/lookup-stage.js +0 -73
- package/dist/translator/stages/lookup-stage.js.map +0 -1
- package/dist/translator/stages/match-stage.d.ts +0 -7
- package/dist/translator/stages/match-stage.d.ts.map +0 -1
- package/dist/translator/stages/match-stage.js +0 -14
- package/dist/translator/stages/match-stage.js.map +0 -1
- package/dist/translator/stages/optimizer.d.ts +0 -15
- package/dist/translator/stages/optimizer.d.ts.map +0 -1
- package/dist/translator/stages/optimizer.js +0 -249
- package/dist/translator/stages/optimizer.js.map +0 -1
- package/dist/translator/stages/parallel-facet.d.ts +0 -47
- package/dist/translator/stages/parallel-facet.d.ts.map +0 -1
- package/dist/translator/stages/parallel-facet.js +0 -57
- package/dist/translator/stages/parallel-facet.js.map +0 -1
- package/dist/translator/stages/project-stage.d.ts +0 -8
- package/dist/translator/stages/project-stage.d.ts.map +0 -1
- package/dist/translator/stages/project-stage.js +0 -145
- package/dist/translator/stages/project-stage.js.map +0 -1
- package/dist/translator/stages/search-stage.d.ts +0 -60
- package/dist/translator/stages/search-stage.d.ts.map +0 -1
- package/dist/translator/stages/search-stage.js +0 -89
- package/dist/translator/stages/search-stage.js.map +0 -1
- package/dist/translator/stages/skip-stage.d.ts +0 -7
- package/dist/translator/stages/skip-stage.d.ts.map +0 -1
- package/dist/translator/stages/skip-stage.js +0 -11
- package/dist/translator/stages/skip-stage.js.map +0 -1
- package/dist/translator/stages/sort-stage.d.ts +0 -7
- package/dist/translator/stages/sort-stage.d.ts.map +0 -1
- package/dist/translator/stages/sort-stage.js +0 -21
- package/dist/translator/stages/sort-stage.js.map +0 -1
- package/dist/translator/stages/types.d.ts +0 -136
- package/dist/translator/stages/types.d.ts.map +0 -1
- package/dist/translator/stages/types.js +0 -5
- package/dist/translator/stages/types.js.map +0 -1
- package/dist/translator/stages/unwind-stage.d.ts +0 -7
- package/dist/translator/stages/unwind-stage.d.ts.map +0 -1
- package/dist/translator/stages/unwind-stage.js +0 -61
- package/dist/translator/stages/unwind-stage.js.map +0 -1
- package/dist/translator/stages/vector-search-stage.d.ts +0 -53
- package/dist/translator/stages/vector-search-stage.d.ts.map +0 -1
- package/dist/translator/stages/vector-search-stage.js +0 -62
- package/dist/translator/stages/vector-search-stage.js.map +0 -1
- package/dist/translator/update-translator.d.ts +0 -148
- package/dist/translator/update-translator.d.ts.map +0 -1
- package/dist/translator/update-translator.js +0 -819
- package/dist/translator/update-translator.js.map +0 -1
- package/dist/translator/vector-translator.d.ts +0 -89
- package/dist/translator/vector-translator.d.ts.map +0 -1
- package/dist/translator/vector-translator.js +0 -106
- package/dist/translator/vector-translator.js.map +0 -1
- package/dist/types/env.d.ts +0 -31
- package/dist/types/env.d.ts.map +0 -1
- package/dist/types/env.js +0 -5
- package/dist/types/env.js.map +0 -1
- package/dist/types/function.d.ts +0 -65
- package/dist/types/function.d.ts.map +0 -1
- package/dist/types/function.js +0 -5
- package/dist/types/function.js.map +0 -1
- package/dist/types/index.d.ts +0 -137
- package/dist/types/index.d.ts.map +0 -1
- package/dist/types/index.js +0 -13
- package/dist/types/index.js.map +0 -1
- package/dist/types/mongodb.d.ts +0 -258
- package/dist/types/mongodb.d.ts.map +0 -1
- package/dist/types/mongodb.js +0 -5
- package/dist/types/mongodb.js.map +0 -1
- package/dist/types/objectid.d.ts +0 -130
- package/dist/types/objectid.d.ts.map +0 -1
- package/dist/types/objectid.js +0 -314
- package/dist/types/objectid.js.map +0 -1
- package/dist/types/rpc.d.ts +0 -313
- package/dist/types/rpc.d.ts.map +0 -1
- package/dist/types/rpc.js +0 -136
- package/dist/types/rpc.js.map +0 -1
- package/dist/types/vectorize.d.ts +0 -136
- package/dist/types/vectorize.d.ts.map +0 -1
- package/dist/types/vectorize.js +0 -8
- package/dist/types/vectorize.js.map +0 -1
- package/dist/utils/sql-safety.d.ts +0 -64
- package/dist/utils/sql-safety.d.ts.map +0 -1
- package/dist/utils/sql-safety.js +0 -112
- package/dist/utils/sql-safety.js.map +0 -1
- package/dist/validation/document-validator.d.ts +0 -195
- package/dist/validation/document-validator.d.ts.map +0 -1
- package/dist/validation/document-validator.js +0 -529
- package/dist/validation/document-validator.js.map +0 -1
- package/dist/vectorize/document-serializer.d.ts +0 -119
- package/dist/vectorize/document-serializer.d.ts.map +0 -1
- package/dist/vectorize/document-serializer.js +0 -320
- package/dist/vectorize/document-serializer.js.map +0 -1
- package/dist/wire/auth/index.d.ts +0 -5
- package/dist/wire/auth/index.d.ts.map +0 -1
- package/dist/wire/auth/index.js +0 -5
- package/dist/wire/auth/index.js.map +0 -1
- package/dist/wire/auth/scram.d.ts +0 -160
- package/dist/wire/auth/scram.d.ts.map +0 -1
- package/dist/wire/auth/scram.js +0 -425
- package/dist/wire/auth/scram.js.map +0 -1
- package/dist/wire/backend/interface.d.ts +0 -168
- package/dist/wire/backend/interface.d.ts.map +0 -1
- package/dist/wire/backend/interface.js +0 -10
- package/dist/wire/backend/interface.js.map +0 -1
- package/dist/wire/backend/local-sqlite.d.ts +0 -89
- package/dist/wire/backend/local-sqlite.d.ts.map +0 -1
- package/dist/wire/backend/local-sqlite.js +0 -1002
- package/dist/wire/backend/local-sqlite.js.map +0 -1
- package/dist/wire/backend/query-router.d.ts +0 -197
- package/dist/wire/backend/query-router.d.ts.map +0 -1
- package/dist/wire/backend/query-router.js +0 -590
- package/dist/wire/backend/query-router.js.map +0 -1
- package/dist/wire/backend/validation.d.ts +0 -26
- package/dist/wire/backend/validation.d.ts.map +0 -1
- package/dist/wire/backend/validation.js +0 -79
- package/dist/wire/backend/validation.js.map +0 -1
- package/dist/wire/backend/workers-proxy.d.ts +0 -95
- package/dist/wire/backend/workers-proxy.d.ts.map +0 -1
- package/dist/wire/backend/workers-proxy.js +0 -429
- package/dist/wire/backend/workers-proxy.js.map +0 -1
- package/dist/wire/commands/admin.d.ts +0 -49
- package/dist/wire/commands/admin.d.ts.map +0 -1
- package/dist/wire/commands/admin.js +0 -272
- package/dist/wire/commands/admin.js.map +0 -1
- package/dist/wire/commands/aggregate.d.ts +0 -15
- package/dist/wire/commands/aggregate.d.ts.map +0 -1
- package/dist/wire/commands/aggregate.js +0 -98
- package/dist/wire/commands/aggregate.js.map +0 -1
- package/dist/wire/commands/auth.d.ts +0 -58
- package/dist/wire/commands/auth.d.ts.map +0 -1
- package/dist/wire/commands/auth.js +0 -158
- package/dist/wire/commands/auth.js.map +0 -1
- package/dist/wire/commands/crud.d.ts +0 -49
- package/dist/wire/commands/crud.d.ts.map +0 -1
- package/dist/wire/commands/crud.js +0 -336
- package/dist/wire/commands/crud.js.map +0 -1
- package/dist/wire/commands/hello.d.ts +0 -35
- package/dist/wire/commands/hello.d.ts.map +0 -1
- package/dist/wire/commands/hello.js +0 -204
- package/dist/wire/commands/hello.js.map +0 -1
- package/dist/wire/commands/index.d.ts +0 -24
- package/dist/wire/commands/index.d.ts.map +0 -1
- package/dist/wire/commands/index.js +0 -145
- package/dist/wire/commands/index.js.map +0 -1
- package/dist/wire/commands/router.d.ts +0 -46
- package/dist/wire/commands/router.d.ts.map +0 -1
- package/dist/wire/commands/router.js +0 -151
- package/dist/wire/commands/router.js.map +0 -1
- package/dist/wire/commands/types.d.ts +0 -51
- package/dist/wire/commands/types.d.ts.map +0 -1
- package/dist/wire/commands/types.js +0 -15
- package/dist/wire/commands/types.js.map +0 -1
- package/dist/wire/index.d.ts +0 -15
- package/dist/wire/index.d.ts.map +0 -1
- package/dist/wire/index.js +0 -19
- package/dist/wire/index.js.map +0 -1
- package/dist/wire/message.d.ts +0 -49
- package/dist/wire/message.d.ts.map +0 -1
- package/dist/wire/message.js +0 -299
- package/dist/wire/message.js.map +0 -1
- package/dist/wire/server.d.ts +0 -145
- package/dist/wire/server.d.ts.map +0 -1
- package/dist/wire/server.js +0 -284
- package/dist/wire/server.js.map +0 -1
- package/dist/wire/types.d.ts +0 -140
- package/dist/wire/types.d.ts.map +0 -1
- package/dist/wire/types.js +0 -64
- package/dist/wire/types.js.map +0 -1
- package/dist/worker.d.ts.map +0 -1
|
@@ -1,1641 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* MongoCollection - MongoDB-compatible collection interface
|
|
3
|
-
*
|
|
4
|
-
* Provides CRUD operations and query support for documents.
|
|
5
|
-
* This is the client-side in-memory implementation for testing.
|
|
6
|
-
*/
|
|
7
|
-
import { ObjectId } from '../types/objectid';
|
|
8
|
-
import { FindCursor } from './cursor';
|
|
9
|
-
import { BulkWriteException, isInsertOneModel, isUpdateOneModel, isUpdateManyModel, isReplaceOneModel, isDeleteOneModel, isDeleteManyModel, } from './bulk-write';
|
|
10
|
-
import { ChangeStream, ChangeEventStore, } from './change-stream';
|
|
11
|
-
import { AggregationCursor, } from './aggregation-cursor';
|
|
12
|
-
/**
|
|
13
|
-
* MongoCollection provides CRUD operations for documents
|
|
14
|
-
*/
|
|
15
|
-
export class MongoCollection {
|
|
16
|
-
database;
|
|
17
|
-
_collectionName;
|
|
18
|
-
documents = new Map();
|
|
19
|
-
_changeEventStore = new ChangeEventStore();
|
|
20
|
-
_activeChangeStreams = new Set();
|
|
21
|
-
constructor(database, name) {
|
|
22
|
-
this.database = database;
|
|
23
|
-
this._collectionName = name;
|
|
24
|
-
}
|
|
25
|
-
/**
|
|
26
|
-
* Get the collection name
|
|
27
|
-
*/
|
|
28
|
-
get collectionName() {
|
|
29
|
-
return this._collectionName;
|
|
30
|
-
}
|
|
31
|
-
/**
|
|
32
|
-
* Ensure collection is created in the database
|
|
33
|
-
* @internal
|
|
34
|
-
*/
|
|
35
|
-
async _ensureCreated() {
|
|
36
|
-
this.database._registerCollection(this._collectionName);
|
|
37
|
-
}
|
|
38
|
-
/**
|
|
39
|
-
* Drop collection data
|
|
40
|
-
* @internal
|
|
41
|
-
*/
|
|
42
|
-
async _drop() {
|
|
43
|
-
this.documents.clear();
|
|
44
|
-
}
|
|
45
|
-
/**
|
|
46
|
-
* Get a unique key for this collection (used for transaction tracking)
|
|
47
|
-
* @internal
|
|
48
|
-
*/
|
|
49
|
-
_getCollectionKey() {
|
|
50
|
-
return `${this.database.databaseName}.${this._collectionName}`;
|
|
51
|
-
}
|
|
52
|
-
/**
|
|
53
|
-
* Create a snapshot of the current collection data
|
|
54
|
-
* @internal
|
|
55
|
-
*/
|
|
56
|
-
_createSnapshot() {
|
|
57
|
-
const snapshot = new Map();
|
|
58
|
-
for (const [key, doc] of this.documents) {
|
|
59
|
-
// Deep clone the document
|
|
60
|
-
snapshot.set(key, JSON.parse(JSON.stringify(doc)));
|
|
61
|
-
}
|
|
62
|
-
return snapshot;
|
|
63
|
-
}
|
|
64
|
-
/**
|
|
65
|
-
* Restore collection data from a snapshot (used for transaction rollback)
|
|
66
|
-
* @internal
|
|
67
|
-
*/
|
|
68
|
-
_restoreFromSnapshot(snapshot) {
|
|
69
|
-
this.documents.clear();
|
|
70
|
-
for (const [key, doc] of snapshot) {
|
|
71
|
-
// Reconstruct ObjectId for _id field
|
|
72
|
-
const restoredDoc = { ...doc };
|
|
73
|
-
if (doc._id && typeof doc._id === 'object' && '_hexString' in doc._id) {
|
|
74
|
-
restoredDoc._id = new ObjectId(doc._id._hexString);
|
|
75
|
-
}
|
|
76
|
-
this.documents.set(key, restoredDoc);
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
/**
|
|
80
|
-
* Track this collection in a session for transaction support
|
|
81
|
-
* @internal
|
|
82
|
-
*/
|
|
83
|
-
_trackInSession(session) {
|
|
84
|
-
if (session && session.inTransaction) {
|
|
85
|
-
session._trackCollection(this);
|
|
86
|
-
session._markInProgress();
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
/**
|
|
90
|
-
* Insert a single document
|
|
91
|
-
*/
|
|
92
|
-
async insertOne(doc, options) {
|
|
93
|
-
await this._ensureCreated();
|
|
94
|
-
// Track collection in session for transaction rollback support
|
|
95
|
-
this._trackInSession(options?.session);
|
|
96
|
-
// Generate _id if not provided
|
|
97
|
-
const docWithId = { ...doc };
|
|
98
|
-
if (!docWithId._id) {
|
|
99
|
-
docWithId._id = new ObjectId();
|
|
100
|
-
}
|
|
101
|
-
else if (typeof docWithId._id === 'string') {
|
|
102
|
-
docWithId._id = new ObjectId(docWithId._id);
|
|
103
|
-
}
|
|
104
|
-
// Check for duplicate _id
|
|
105
|
-
const idHex = docWithId._id.toHexString();
|
|
106
|
-
if (this.documents.has(idHex)) {
|
|
107
|
-
const error = new Error(`E11000 duplicate key error collection: ${this._collectionName} dup key: { _id: "${idHex}" }`);
|
|
108
|
-
error.code = 11000;
|
|
109
|
-
throw error;
|
|
110
|
-
}
|
|
111
|
-
// Store document
|
|
112
|
-
this.documents.set(idHex, docWithId);
|
|
113
|
-
// Emit insert change event
|
|
114
|
-
this._changeEventStore.addEvent({
|
|
115
|
-
operationType: 'insert',
|
|
116
|
-
documentId: docWithId._id,
|
|
117
|
-
fullDocument: docWithId,
|
|
118
|
-
});
|
|
119
|
-
return {
|
|
120
|
-
acknowledged: true,
|
|
121
|
-
insertedId: docWithId._id,
|
|
122
|
-
};
|
|
123
|
-
}
|
|
124
|
-
/**
|
|
125
|
-
* Insert multiple documents
|
|
126
|
-
*/
|
|
127
|
-
async insertMany(docs, options) {
|
|
128
|
-
await this._ensureCreated();
|
|
129
|
-
// Track collection in session for transaction rollback support
|
|
130
|
-
this._trackInSession(options?.session);
|
|
131
|
-
const insertedIds = {};
|
|
132
|
-
for (let i = 0; i < docs.length; i++) {
|
|
133
|
-
const doc = docs[i];
|
|
134
|
-
if (doc === undefined)
|
|
135
|
-
continue;
|
|
136
|
-
const result = await this.insertOne(doc, options);
|
|
137
|
-
insertedIds[i] = result.insertedId;
|
|
138
|
-
}
|
|
139
|
-
return {
|
|
140
|
-
acknowledged: true,
|
|
141
|
-
insertedCount: docs.length,
|
|
142
|
-
insertedIds,
|
|
143
|
-
};
|
|
144
|
-
}
|
|
145
|
-
/**
|
|
146
|
-
* Find a single document
|
|
147
|
-
*/
|
|
148
|
-
async findOne(filter = {}, options) {
|
|
149
|
-
const docs = this._findDocuments(filter);
|
|
150
|
-
if (docs.length === 0) {
|
|
151
|
-
return null;
|
|
152
|
-
}
|
|
153
|
-
const doc = docs[0];
|
|
154
|
-
if (doc === undefined) {
|
|
155
|
-
return null;
|
|
156
|
-
}
|
|
157
|
-
return options?.projection ? this._applyProjection(doc, options.projection) : doc;
|
|
158
|
-
}
|
|
159
|
-
/**
|
|
160
|
-
* Find multiple documents, returns a cursor
|
|
161
|
-
*/
|
|
162
|
-
find(filter = {}, options) {
|
|
163
|
-
// Convert to a clean object to avoid exactOptionalPropertyTypes issues
|
|
164
|
-
const cursorOptions = options ? {
|
|
165
|
-
...(options.projection !== undefined && { projection: options.projection }),
|
|
166
|
-
...(options.sort !== undefined && { sort: options.sort }),
|
|
167
|
-
...(options.limit !== undefined && { limit: options.limit }),
|
|
168
|
-
...(options.skip !== undefined && { skip: options.skip }),
|
|
169
|
-
} : undefined;
|
|
170
|
-
return new FindCursor(this, filter, cursorOptions);
|
|
171
|
-
}
|
|
172
|
-
/**
|
|
173
|
-
* Internal method to execute find query
|
|
174
|
-
* @internal
|
|
175
|
-
*/
|
|
176
|
-
_findDocuments(filter, options) {
|
|
177
|
-
let results = [];
|
|
178
|
-
// Get all documents and filter
|
|
179
|
-
for (const doc of this.documents.values()) {
|
|
180
|
-
if (this._matchesFilter(doc, filter)) {
|
|
181
|
-
results.push({ ...doc });
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
// Apply sort
|
|
185
|
-
if (options?.sort) {
|
|
186
|
-
results = this._sortDocuments(results, options.sort);
|
|
187
|
-
}
|
|
188
|
-
// Apply skip
|
|
189
|
-
if (options?.skip && options.skip > 0) {
|
|
190
|
-
results = results.slice(options.skip);
|
|
191
|
-
}
|
|
192
|
-
// Apply limit
|
|
193
|
-
if (options?.limit && options.limit > 0) {
|
|
194
|
-
results = results.slice(0, options.limit);
|
|
195
|
-
}
|
|
196
|
-
return results;
|
|
197
|
-
}
|
|
198
|
-
/**
|
|
199
|
-
* Update a single document
|
|
200
|
-
*/
|
|
201
|
-
async updateOne(filter, update, options) {
|
|
202
|
-
// Track collection in session for transaction rollback support
|
|
203
|
-
this._trackInSession(options?.session);
|
|
204
|
-
const docs = this._findDocuments(filter);
|
|
205
|
-
if (docs.length === 0) {
|
|
206
|
-
// Handle upsert
|
|
207
|
-
if (options?.upsert) {
|
|
208
|
-
const newDoc = this._applyUpdate({}, update, filter);
|
|
209
|
-
const result = await this.insertOne(newDoc, options);
|
|
210
|
-
return {
|
|
211
|
-
acknowledged: true,
|
|
212
|
-
matchedCount: 0,
|
|
213
|
-
modifiedCount: 0,
|
|
214
|
-
upsertedId: result.insertedId,
|
|
215
|
-
upsertedCount: 1,
|
|
216
|
-
};
|
|
217
|
-
}
|
|
218
|
-
return {
|
|
219
|
-
acknowledged: true,
|
|
220
|
-
matchedCount: 0,
|
|
221
|
-
modifiedCount: 0,
|
|
222
|
-
};
|
|
223
|
-
}
|
|
224
|
-
// Update first matching document
|
|
225
|
-
const doc = docs[0];
|
|
226
|
-
if (doc === undefined) {
|
|
227
|
-
return {
|
|
228
|
-
acknowledged: true,
|
|
229
|
-
matchedCount: 0,
|
|
230
|
-
modifiedCount: 0,
|
|
231
|
-
};
|
|
232
|
-
}
|
|
233
|
-
const updatedDoc = this._applyUpdate(doc, update);
|
|
234
|
-
this.documents.set(doc._id.toHexString(), updatedDoc);
|
|
235
|
-
// Emit update change event
|
|
236
|
-
const { updatedFields, removedFields } = this._extractUpdateChanges(update);
|
|
237
|
-
this._changeEventStore.addEvent({
|
|
238
|
-
operationType: 'update',
|
|
239
|
-
documentId: doc._id,
|
|
240
|
-
updatedFields,
|
|
241
|
-
removedFields,
|
|
242
|
-
});
|
|
243
|
-
return {
|
|
244
|
-
acknowledged: true,
|
|
245
|
-
matchedCount: 1,
|
|
246
|
-
modifiedCount: 1,
|
|
247
|
-
};
|
|
248
|
-
}
|
|
249
|
-
/**
|
|
250
|
-
* Update multiple documents
|
|
251
|
-
*/
|
|
252
|
-
async updateMany(filter, update, options) {
|
|
253
|
-
// Track collection in session for transaction rollback support
|
|
254
|
-
this._trackInSession(options?.session);
|
|
255
|
-
const docs = this._findDocuments(filter);
|
|
256
|
-
if (docs.length === 0) {
|
|
257
|
-
if (options?.upsert) {
|
|
258
|
-
const newDoc = this._applyUpdate({}, update, filter);
|
|
259
|
-
const result = await this.insertOne(newDoc, options);
|
|
260
|
-
return {
|
|
261
|
-
acknowledged: true,
|
|
262
|
-
matchedCount: 0,
|
|
263
|
-
modifiedCount: 0,
|
|
264
|
-
upsertedId: result.insertedId,
|
|
265
|
-
upsertedCount: 1,
|
|
266
|
-
};
|
|
267
|
-
}
|
|
268
|
-
return {
|
|
269
|
-
acknowledged: true,
|
|
270
|
-
matchedCount: 0,
|
|
271
|
-
modifiedCount: 0,
|
|
272
|
-
};
|
|
273
|
-
}
|
|
274
|
-
// Update all matching documents
|
|
275
|
-
const { updatedFields, removedFields } = this._extractUpdateChanges(update);
|
|
276
|
-
for (const doc of docs) {
|
|
277
|
-
const updatedDoc = this._applyUpdate(doc, update);
|
|
278
|
-
this.documents.set(doc._id.toHexString(), updatedDoc);
|
|
279
|
-
// Emit update change event for each document
|
|
280
|
-
this._changeEventStore.addEvent({
|
|
281
|
-
operationType: 'update',
|
|
282
|
-
documentId: doc._id,
|
|
283
|
-
updatedFields,
|
|
284
|
-
removedFields,
|
|
285
|
-
});
|
|
286
|
-
}
|
|
287
|
-
return {
|
|
288
|
-
acknowledged: true,
|
|
289
|
-
matchedCount: docs.length,
|
|
290
|
-
modifiedCount: docs.length,
|
|
291
|
-
};
|
|
292
|
-
}
|
|
293
|
-
/**
|
|
294
|
-
* Replace a single document
|
|
295
|
-
*/
|
|
296
|
-
async replaceOne(filter, replacement, options) {
|
|
297
|
-
// Track collection in session for transaction rollback support
|
|
298
|
-
this._trackInSession(options?.session);
|
|
299
|
-
const docs = this._findDocuments(filter);
|
|
300
|
-
if (docs.length === 0) {
|
|
301
|
-
if (options?.upsert) {
|
|
302
|
-
const result = await this.insertOne(replacement, options);
|
|
303
|
-
return {
|
|
304
|
-
acknowledged: true,
|
|
305
|
-
matchedCount: 0,
|
|
306
|
-
modifiedCount: 0,
|
|
307
|
-
upsertedId: result.insertedId,
|
|
308
|
-
upsertedCount: 1,
|
|
309
|
-
};
|
|
310
|
-
}
|
|
311
|
-
return {
|
|
312
|
-
acknowledged: true,
|
|
313
|
-
matchedCount: 0,
|
|
314
|
-
modifiedCount: 0,
|
|
315
|
-
};
|
|
316
|
-
}
|
|
317
|
-
// Replace first matching document, preserving _id
|
|
318
|
-
const doc = docs[0];
|
|
319
|
-
if (doc === undefined) {
|
|
320
|
-
return {
|
|
321
|
-
acknowledged: true,
|
|
322
|
-
matchedCount: 0,
|
|
323
|
-
modifiedCount: 0,
|
|
324
|
-
};
|
|
325
|
-
}
|
|
326
|
-
const replacedDoc = { ...replacement, _id: doc._id };
|
|
327
|
-
this.documents.set(doc._id.toHexString(), replacedDoc);
|
|
328
|
-
// Emit replace change event
|
|
329
|
-
this._changeEventStore.addEvent({
|
|
330
|
-
operationType: 'replace',
|
|
331
|
-
documentId: doc._id,
|
|
332
|
-
fullDocument: replacedDoc,
|
|
333
|
-
});
|
|
334
|
-
return {
|
|
335
|
-
acknowledged: true,
|
|
336
|
-
matchedCount: 1,
|
|
337
|
-
modifiedCount: 1,
|
|
338
|
-
};
|
|
339
|
-
}
|
|
340
|
-
/**
|
|
341
|
-
* Delete a single document
|
|
342
|
-
*/
|
|
343
|
-
async deleteOne(filter, options) {
|
|
344
|
-
// Track collection in session for transaction rollback support
|
|
345
|
-
this._trackInSession(options?.session);
|
|
346
|
-
const docs = this._findDocuments(filter);
|
|
347
|
-
if (docs.length === 0) {
|
|
348
|
-
return {
|
|
349
|
-
acknowledged: true,
|
|
350
|
-
deletedCount: 0,
|
|
351
|
-
};
|
|
352
|
-
}
|
|
353
|
-
// Delete first matching document
|
|
354
|
-
const firstDoc = docs[0];
|
|
355
|
-
if (firstDoc === undefined) {
|
|
356
|
-
return {
|
|
357
|
-
acknowledged: true,
|
|
358
|
-
deletedCount: 0,
|
|
359
|
-
};
|
|
360
|
-
}
|
|
361
|
-
const docId = firstDoc._id;
|
|
362
|
-
this.documents.delete(docId.toHexString());
|
|
363
|
-
// Emit delete change event
|
|
364
|
-
this._changeEventStore.addEvent({
|
|
365
|
-
operationType: 'delete',
|
|
366
|
-
documentId: docId,
|
|
367
|
-
});
|
|
368
|
-
return {
|
|
369
|
-
acknowledged: true,
|
|
370
|
-
deletedCount: 1,
|
|
371
|
-
};
|
|
372
|
-
}
|
|
373
|
-
/**
|
|
374
|
-
* Delete multiple documents
|
|
375
|
-
*/
|
|
376
|
-
async deleteMany(filter, options) {
|
|
377
|
-
// Track collection in session for transaction rollback support
|
|
378
|
-
this._trackInSession(options?.session);
|
|
379
|
-
const docs = this._findDocuments(filter);
|
|
380
|
-
// Delete all matching documents
|
|
381
|
-
for (const doc of docs) {
|
|
382
|
-
this.documents.delete(doc._id.toHexString());
|
|
383
|
-
// Emit delete change event
|
|
384
|
-
this._changeEventStore.addEvent({
|
|
385
|
-
operationType: 'delete',
|
|
386
|
-
documentId: doc._id,
|
|
387
|
-
});
|
|
388
|
-
}
|
|
389
|
-
return {
|
|
390
|
-
acknowledged: true,
|
|
391
|
-
deletedCount: docs.length,
|
|
392
|
-
};
|
|
393
|
-
}
|
|
394
|
-
/**
|
|
395
|
-
* Count documents matching filter
|
|
396
|
-
*/
|
|
397
|
-
async countDocuments(filter = {}) {
|
|
398
|
-
const docs = this._findDocuments(filter);
|
|
399
|
-
return docs.length;
|
|
400
|
-
}
|
|
401
|
-
/**
|
|
402
|
-
* Find one and update
|
|
403
|
-
*/
|
|
404
|
-
async findOneAndUpdate(filter, update, options) {
|
|
405
|
-
const docs = this._findDocuments(filter, {
|
|
406
|
-
...(options?.sort !== undefined && { sort: options.sort })
|
|
407
|
-
});
|
|
408
|
-
if (docs.length === 0) {
|
|
409
|
-
if (options?.upsert) {
|
|
410
|
-
const newDoc = this._applyUpdate({}, update, filter);
|
|
411
|
-
await this.insertOne(newDoc);
|
|
412
|
-
if (options?.returnDocument === 'after') {
|
|
413
|
-
return this.findOne(filter, {
|
|
414
|
-
...(options?.projection !== undefined && { projection: options.projection })
|
|
415
|
-
});
|
|
416
|
-
}
|
|
417
|
-
return null;
|
|
418
|
-
}
|
|
419
|
-
return null;
|
|
420
|
-
}
|
|
421
|
-
const doc = docs[0];
|
|
422
|
-
if (doc === undefined) {
|
|
423
|
-
return null;
|
|
424
|
-
}
|
|
425
|
-
const originalDoc = { ...doc };
|
|
426
|
-
// Update the document
|
|
427
|
-
const updatedDoc = this._applyUpdate(doc, update);
|
|
428
|
-
this.documents.set(doc._id.toHexString(), updatedDoc);
|
|
429
|
-
// Return before or after based on options
|
|
430
|
-
const result = options?.returnDocument === 'after' ? updatedDoc : originalDoc;
|
|
431
|
-
return options?.projection ? this._applyProjection(result, options.projection) : result;
|
|
432
|
-
}
|
|
433
|
-
/**
|
|
434
|
-
* Find one and delete
|
|
435
|
-
*/
|
|
436
|
-
async findOneAndDelete(filter, options) {
|
|
437
|
-
const docs = this._findDocuments(filter, {
|
|
438
|
-
...(options?.sort !== undefined && { sort: options.sort })
|
|
439
|
-
});
|
|
440
|
-
if (docs.length === 0) {
|
|
441
|
-
return null;
|
|
442
|
-
}
|
|
443
|
-
const doc = docs[0];
|
|
444
|
-
if (doc === undefined) {
|
|
445
|
-
return null;
|
|
446
|
-
}
|
|
447
|
-
this.documents.delete(doc._id.toHexString());
|
|
448
|
-
return options?.projection ? this._applyProjection(doc, options.projection) : doc;
|
|
449
|
-
}
|
|
450
|
-
/**
|
|
451
|
-
* Find one and replace
|
|
452
|
-
*/
|
|
453
|
-
async findOneAndReplace(filter, replacement, options) {
|
|
454
|
-
const docs = this._findDocuments(filter, {
|
|
455
|
-
...(options?.sort !== undefined && { sort: options.sort })
|
|
456
|
-
});
|
|
457
|
-
if (docs.length === 0) {
|
|
458
|
-
if (options?.upsert) {
|
|
459
|
-
await this.insertOne(replacement);
|
|
460
|
-
if (options?.returnDocument === 'after') {
|
|
461
|
-
return this.findOne(filter, {
|
|
462
|
-
...(options?.projection !== undefined && { projection: options.projection })
|
|
463
|
-
});
|
|
464
|
-
}
|
|
465
|
-
return null;
|
|
466
|
-
}
|
|
467
|
-
return null;
|
|
468
|
-
}
|
|
469
|
-
const doc = docs[0];
|
|
470
|
-
if (doc === undefined) {
|
|
471
|
-
return null;
|
|
472
|
-
}
|
|
473
|
-
const originalDoc = { ...doc };
|
|
474
|
-
// Replace the document, preserving _id
|
|
475
|
-
const replacedDoc = { ...replacement, _id: doc._id };
|
|
476
|
-
this.documents.set(doc._id.toHexString(), replacedDoc);
|
|
477
|
-
// Return before or after based on options
|
|
478
|
-
const result = options?.returnDocument === 'after' ? replacedDoc : originalDoc;
|
|
479
|
-
return options?.projection ? this._applyProjection(result, options.projection) : result;
|
|
480
|
-
}
|
|
481
|
-
/**
|
|
482
|
-
* Execute multiple write operations in a single batch
|
|
483
|
-
*
|
|
484
|
-
* @param operations - Array of bulk write operations
|
|
485
|
-
* @param options - Bulk write options
|
|
486
|
-
* @returns BulkWriteResult with operation counts
|
|
487
|
-
*/
|
|
488
|
-
async bulkWrite(operations, options = {}) {
|
|
489
|
-
const ordered = options.ordered !== false; // Default to true
|
|
490
|
-
// Initialize result
|
|
491
|
-
const result = {
|
|
492
|
-
acknowledged: true,
|
|
493
|
-
insertedCount: 0,
|
|
494
|
-
matchedCount: 0,
|
|
495
|
-
modifiedCount: 0,
|
|
496
|
-
deletedCount: 0,
|
|
497
|
-
upsertedCount: 0,
|
|
498
|
-
insertedIds: {},
|
|
499
|
-
upsertedIds: {},
|
|
500
|
-
};
|
|
501
|
-
const writeErrors = [];
|
|
502
|
-
// Process operations
|
|
503
|
-
for (let i = 0; i < operations.length; i++) {
|
|
504
|
-
const op = operations[i];
|
|
505
|
-
if (op === undefined)
|
|
506
|
-
continue;
|
|
507
|
-
try {
|
|
508
|
-
if (isInsertOneModel(op)) {
|
|
509
|
-
const insertResult = await this.insertOne(op.insertOne.document);
|
|
510
|
-
result.insertedCount++;
|
|
511
|
-
result.insertedIds[i] = insertResult.insertedId;
|
|
512
|
-
}
|
|
513
|
-
else if (isUpdateOneModel(op)) {
|
|
514
|
-
const updateResult = await this.updateOne(op.updateOne.filter, op.updateOne.update, {
|
|
515
|
-
...(op.updateOne.upsert !== undefined && { upsert: op.updateOne.upsert }),
|
|
516
|
-
...(op.updateOne.arrayFilters !== undefined && { arrayFilters: op.updateOne.arrayFilters })
|
|
517
|
-
});
|
|
518
|
-
result.matchedCount += updateResult.matchedCount;
|
|
519
|
-
result.modifiedCount += updateResult.modifiedCount;
|
|
520
|
-
if (updateResult.upsertedId) {
|
|
521
|
-
result.upsertedCount++;
|
|
522
|
-
result.upsertedIds[i] = updateResult.upsertedId;
|
|
523
|
-
}
|
|
524
|
-
}
|
|
525
|
-
else if (isUpdateManyModel(op)) {
|
|
526
|
-
const updateResult = await this.updateMany(op.updateMany.filter, op.updateMany.update, {
|
|
527
|
-
...(op.updateMany.upsert !== undefined && { upsert: op.updateMany.upsert }),
|
|
528
|
-
...(op.updateMany.arrayFilters !== undefined && { arrayFilters: op.updateMany.arrayFilters })
|
|
529
|
-
});
|
|
530
|
-
result.matchedCount += updateResult.matchedCount;
|
|
531
|
-
result.modifiedCount += updateResult.modifiedCount;
|
|
532
|
-
if (updateResult.upsertedId) {
|
|
533
|
-
result.upsertedCount++;
|
|
534
|
-
result.upsertedIds[i] = updateResult.upsertedId;
|
|
535
|
-
}
|
|
536
|
-
}
|
|
537
|
-
else if (isReplaceOneModel(op)) {
|
|
538
|
-
const replaceResult = await this.replaceOne(op.replaceOne.filter, op.replaceOne.replacement, {
|
|
539
|
-
...(op.replaceOne.upsert !== undefined && { upsert: op.replaceOne.upsert })
|
|
540
|
-
});
|
|
541
|
-
result.matchedCount += replaceResult.matchedCount;
|
|
542
|
-
result.modifiedCount += replaceResult.modifiedCount;
|
|
543
|
-
if (replaceResult.upsertedId) {
|
|
544
|
-
result.upsertedCount++;
|
|
545
|
-
result.upsertedIds[i] = replaceResult.upsertedId;
|
|
546
|
-
}
|
|
547
|
-
}
|
|
548
|
-
else if (isDeleteOneModel(op)) {
|
|
549
|
-
const deleteResult = await this.deleteOne(op.deleteOne.filter);
|
|
550
|
-
result.deletedCount += deleteResult.deletedCount;
|
|
551
|
-
}
|
|
552
|
-
else if (isDeleteManyModel(op)) {
|
|
553
|
-
const deleteResult = await this.deleteMany(op.deleteMany.filter);
|
|
554
|
-
result.deletedCount += deleteResult.deletedCount;
|
|
555
|
-
}
|
|
556
|
-
}
|
|
557
|
-
catch (error) {
|
|
558
|
-
const bulkError = {
|
|
559
|
-
index: i,
|
|
560
|
-
code: 11000, // Default to duplicate key error code
|
|
561
|
-
errmsg: error instanceof Error ? error.message : String(error),
|
|
562
|
-
op,
|
|
563
|
-
};
|
|
564
|
-
writeErrors.push(bulkError);
|
|
565
|
-
// For ordered operations, stop on first error
|
|
566
|
-
if (ordered) {
|
|
567
|
-
throw new BulkWriteException(`BulkWrite operation failed: ${bulkError.errmsg}`, result, writeErrors);
|
|
568
|
-
}
|
|
569
|
-
// For unordered, continue processing remaining operations
|
|
570
|
-
}
|
|
571
|
-
}
|
|
572
|
-
// If there were errors in unordered mode, throw exception with partial results
|
|
573
|
-
if (writeErrors.length > 0) {
|
|
574
|
-
throw new BulkWriteException(`BulkWrite operation completed with ${writeErrors.length} error(s)`, result, writeErrors);
|
|
575
|
-
}
|
|
576
|
-
return result;
|
|
577
|
-
}
|
|
578
|
-
/**
|
|
579
|
-
* Drop the collection
|
|
580
|
-
*/
|
|
581
|
-
async drop() {
|
|
582
|
-
this.documents.clear();
|
|
583
|
-
return true;
|
|
584
|
-
}
|
|
585
|
-
/**
|
|
586
|
-
* Watch for changes on this collection
|
|
587
|
-
*
|
|
588
|
-
* Creates a change stream that emits events for insert, update, replace, and delete operations.
|
|
589
|
-
*
|
|
590
|
-
* @param pipeline - Optional aggregation pipeline for filtering events (supports $match)
|
|
591
|
-
* @param options - Change stream options
|
|
592
|
-
* @returns A ChangeStream instance
|
|
593
|
-
*
|
|
594
|
-
* @example
|
|
595
|
-
* ```typescript
|
|
596
|
-
* const changeStream = collection.watch([
|
|
597
|
-
* { $match: { operationType: 'insert' } }
|
|
598
|
-
* ])
|
|
599
|
-
*
|
|
600
|
-
* for await (const event of changeStream) {
|
|
601
|
-
* console.log('Change:', event.operationType, event.fullDocument)
|
|
602
|
-
* }
|
|
603
|
-
* ```
|
|
604
|
-
*/
|
|
605
|
-
watch(pipeline = [], options = {}) {
|
|
606
|
-
const changeStream = new ChangeStream(this.database.databaseName, this._collectionName, pipeline, options, {
|
|
607
|
-
getDocumentById: async (id) => {
|
|
608
|
-
const doc = this.documents.get(id.toHexString());
|
|
609
|
-
return doc || null;
|
|
610
|
-
},
|
|
611
|
-
getChangeEvents: async (afterSequence) => {
|
|
612
|
-
return this._changeEventStore.getEventsAfter(afterSequence);
|
|
613
|
-
},
|
|
614
|
-
getCurrentSequence: () => {
|
|
615
|
-
return this._changeEventStore.getCurrentSequence();
|
|
616
|
-
},
|
|
617
|
-
onClose: () => {
|
|
618
|
-
this._activeChangeStreams.delete(changeStream);
|
|
619
|
-
},
|
|
620
|
-
});
|
|
621
|
-
this._activeChangeStreams.add(changeStream);
|
|
622
|
-
return changeStream;
|
|
623
|
-
}
|
|
624
|
-
/**
|
|
625
|
-
* Check if a document matches a filter
|
|
626
|
-
* @internal
|
|
627
|
-
*/
|
|
628
|
-
_matchesFilter(doc, filter) {
|
|
629
|
-
const filterObj = filter;
|
|
630
|
-
for (const [key, value] of Object.entries(filterObj)) {
|
|
631
|
-
// Handle logical operators
|
|
632
|
-
if (key === '$and') {
|
|
633
|
-
const conditions = value;
|
|
634
|
-
if (!conditions.every(cond => this._matchesFilter(doc, cond))) {
|
|
635
|
-
return false;
|
|
636
|
-
}
|
|
637
|
-
continue;
|
|
638
|
-
}
|
|
639
|
-
if (key === '$or') {
|
|
640
|
-
const conditions = value;
|
|
641
|
-
if (!conditions.some(cond => this._matchesFilter(doc, cond))) {
|
|
642
|
-
return false;
|
|
643
|
-
}
|
|
644
|
-
continue;
|
|
645
|
-
}
|
|
646
|
-
if (key === '$nor') {
|
|
647
|
-
const conditions = value;
|
|
648
|
-
if (conditions.some(cond => this._matchesFilter(doc, cond))) {
|
|
649
|
-
return false;
|
|
650
|
-
}
|
|
651
|
-
continue;
|
|
652
|
-
}
|
|
653
|
-
// Get document value for comparison
|
|
654
|
-
const docValue = this._getNestedValue(doc, key);
|
|
655
|
-
// Handle operator objects
|
|
656
|
-
if (value !== null && typeof value === 'object' && !Array.isArray(value) && !(value instanceof ObjectId)) {
|
|
657
|
-
if (!this._matchesOperators(docValue, value)) {
|
|
658
|
-
return false;
|
|
659
|
-
}
|
|
660
|
-
continue;
|
|
661
|
-
}
|
|
662
|
-
// Direct comparison
|
|
663
|
-
if (!this._valuesEqual(docValue, value)) {
|
|
664
|
-
return false;
|
|
665
|
-
}
|
|
666
|
-
}
|
|
667
|
-
return true;
|
|
668
|
-
}
|
|
669
|
-
/**
|
|
670
|
-
* Check if a value matches operator conditions
|
|
671
|
-
*/
|
|
672
|
-
_matchesOperators(docValue, operators) {
|
|
673
|
-
for (const [op, opValue] of Object.entries(operators)) {
|
|
674
|
-
switch (op) {
|
|
675
|
-
case '$eq':
|
|
676
|
-
if (!this._valuesEqual(docValue, opValue))
|
|
677
|
-
return false;
|
|
678
|
-
break;
|
|
679
|
-
case '$ne':
|
|
680
|
-
if (this._valuesEqual(docValue, opValue))
|
|
681
|
-
return false;
|
|
682
|
-
break;
|
|
683
|
-
case '$gt':
|
|
684
|
-
if (typeof docValue !== 'number' || docValue <= opValue)
|
|
685
|
-
return false;
|
|
686
|
-
break;
|
|
687
|
-
case '$gte':
|
|
688
|
-
if (typeof docValue !== 'number' || docValue < opValue)
|
|
689
|
-
return false;
|
|
690
|
-
break;
|
|
691
|
-
case '$lt':
|
|
692
|
-
if (typeof docValue !== 'number' || docValue >= opValue)
|
|
693
|
-
return false;
|
|
694
|
-
break;
|
|
695
|
-
case '$lte':
|
|
696
|
-
if (typeof docValue !== 'number' || docValue > opValue)
|
|
697
|
-
return false;
|
|
698
|
-
break;
|
|
699
|
-
case '$in':
|
|
700
|
-
const inArray = opValue;
|
|
701
|
-
if (!inArray.some(v => this._valuesEqual(docValue, v)))
|
|
702
|
-
return false;
|
|
703
|
-
break;
|
|
704
|
-
case '$nin':
|
|
705
|
-
const ninArray = opValue;
|
|
706
|
-
if (ninArray.some(v => this._valuesEqual(docValue, v)))
|
|
707
|
-
return false;
|
|
708
|
-
break;
|
|
709
|
-
case '$exists':
|
|
710
|
-
const exists = docValue !== undefined;
|
|
711
|
-
if (opValue !== exists)
|
|
712
|
-
return false;
|
|
713
|
-
break;
|
|
714
|
-
case '$not':
|
|
715
|
-
if (this._matchesOperators(docValue, opValue))
|
|
716
|
-
return false;
|
|
717
|
-
break;
|
|
718
|
-
case '$regex':
|
|
719
|
-
const regex = new RegExp(opValue);
|
|
720
|
-
if (typeof docValue !== 'string' || !regex.test(docValue))
|
|
721
|
-
return false;
|
|
722
|
-
break;
|
|
723
|
-
case '$type':
|
|
724
|
-
if (typeof docValue !== opValue)
|
|
725
|
-
return false;
|
|
726
|
-
break;
|
|
727
|
-
case '$elemMatch':
|
|
728
|
-
if (!Array.isArray(docValue))
|
|
729
|
-
return false;
|
|
730
|
-
if (!docValue.some(elem => this._matchesFilter(elem, opValue)))
|
|
731
|
-
return false;
|
|
732
|
-
break;
|
|
733
|
-
case '$size':
|
|
734
|
-
if (!Array.isArray(docValue) || docValue.length !== opValue)
|
|
735
|
-
return false;
|
|
736
|
-
break;
|
|
737
|
-
case '$all':
|
|
738
|
-
if (!Array.isArray(docValue))
|
|
739
|
-
return false;
|
|
740
|
-
const allValues = opValue;
|
|
741
|
-
if (!allValues.every(v => docValue.some(dv => this._valuesEqual(dv, v))))
|
|
742
|
-
return false;
|
|
743
|
-
break;
|
|
744
|
-
}
|
|
745
|
-
}
|
|
746
|
-
return true;
|
|
747
|
-
}
|
|
748
|
-
/**
|
|
749
|
-
* Compare two values for equality
|
|
750
|
-
*/
|
|
751
|
-
_valuesEqual(a, b) {
|
|
752
|
-
if (a instanceof ObjectId && b instanceof ObjectId) {
|
|
753
|
-
return a.equals(b);
|
|
754
|
-
}
|
|
755
|
-
if (a instanceof ObjectId && typeof b === 'string') {
|
|
756
|
-
return a.equals(b);
|
|
757
|
-
}
|
|
758
|
-
if (typeof a === 'string' && b instanceof ObjectId) {
|
|
759
|
-
return b.equals(a);
|
|
760
|
-
}
|
|
761
|
-
if (Array.isArray(a) && Array.isArray(b)) {
|
|
762
|
-
if (a.length !== b.length)
|
|
763
|
-
return false;
|
|
764
|
-
return a.every((val, idx) => this._valuesEqual(val, b[idx]));
|
|
765
|
-
}
|
|
766
|
-
if (a !== null && b !== null && typeof a === 'object' && typeof b === 'object') {
|
|
767
|
-
const keysA = Object.keys(a);
|
|
768
|
-
const keysB = Object.keys(b);
|
|
769
|
-
if (keysA.length !== keysB.length)
|
|
770
|
-
return false;
|
|
771
|
-
return keysA.every(key => this._valuesEqual(a[key], b[key]));
|
|
772
|
-
}
|
|
773
|
-
return a === b;
|
|
774
|
-
}
|
|
775
|
-
/**
|
|
776
|
-
* Get nested value from document using dot notation
|
|
777
|
-
*/
|
|
778
|
-
_getNestedValue(doc, path) {
|
|
779
|
-
const parts = path.split('.');
|
|
780
|
-
let current = doc;
|
|
781
|
-
for (const part of parts) {
|
|
782
|
-
if (current === null || current === undefined) {
|
|
783
|
-
return undefined;
|
|
784
|
-
}
|
|
785
|
-
current = current[part];
|
|
786
|
-
}
|
|
787
|
-
return current;
|
|
788
|
-
}
|
|
789
|
-
/**
|
|
790
|
-
* Apply update operators to a document
|
|
791
|
-
*/
|
|
792
|
-
_applyUpdate(doc, update, filter) {
|
|
793
|
-
const updateObj = update;
|
|
794
|
-
const result = { ...doc };
|
|
795
|
-
// Preserve or generate _id
|
|
796
|
-
if (!result._id) {
|
|
797
|
-
result._id = new ObjectId();
|
|
798
|
-
}
|
|
799
|
-
// Apply filter fields for upsert
|
|
800
|
-
if (filter) {
|
|
801
|
-
const filterObj = filter;
|
|
802
|
-
for (const [key, value] of Object.entries(filterObj)) {
|
|
803
|
-
if (!key.startsWith('$') && typeof value !== 'object') {
|
|
804
|
-
result[key] = value;
|
|
805
|
-
}
|
|
806
|
-
}
|
|
807
|
-
}
|
|
808
|
-
// Apply update operators
|
|
809
|
-
for (const [op, fields] of Object.entries(updateObj)) {
|
|
810
|
-
switch (op) {
|
|
811
|
-
case '$set':
|
|
812
|
-
for (const [key, value] of Object.entries(fields)) {
|
|
813
|
-
this._setNestedValue(result, key, value);
|
|
814
|
-
}
|
|
815
|
-
break;
|
|
816
|
-
case '$unset':
|
|
817
|
-
for (const key of Object.keys(fields)) {
|
|
818
|
-
this._deleteNestedValue(result, key);
|
|
819
|
-
}
|
|
820
|
-
break;
|
|
821
|
-
case '$inc':
|
|
822
|
-
for (const [key, value] of Object.entries(fields)) {
|
|
823
|
-
const current = this._getNestedValue(result, key);
|
|
824
|
-
const newValue = (typeof current === 'number' ? current : 0) + value;
|
|
825
|
-
this._setNestedValue(result, key, newValue);
|
|
826
|
-
}
|
|
827
|
-
break;
|
|
828
|
-
case '$mul':
|
|
829
|
-
for (const [key, value] of Object.entries(fields)) {
|
|
830
|
-
const current = this._getNestedValue(result, key);
|
|
831
|
-
const newValue = (typeof current === 'number' ? current : 0) * value;
|
|
832
|
-
this._setNestedValue(result, key, newValue);
|
|
833
|
-
}
|
|
834
|
-
break;
|
|
835
|
-
case '$min':
|
|
836
|
-
for (const [key, value] of Object.entries(fields)) {
|
|
837
|
-
const current = this._getNestedValue(result, key);
|
|
838
|
-
if (current === undefined || value < current) {
|
|
839
|
-
this._setNestedValue(result, key, value);
|
|
840
|
-
}
|
|
841
|
-
}
|
|
842
|
-
break;
|
|
843
|
-
case '$max':
|
|
844
|
-
for (const [key, value] of Object.entries(fields)) {
|
|
845
|
-
const current = this._getNestedValue(result, key);
|
|
846
|
-
if (current === undefined || value > current) {
|
|
847
|
-
this._setNestedValue(result, key, value);
|
|
848
|
-
}
|
|
849
|
-
}
|
|
850
|
-
break;
|
|
851
|
-
case '$rename':
|
|
852
|
-
for (const [oldKey, newKey] of Object.entries(fields)) {
|
|
853
|
-
const value = this._getNestedValue(result, oldKey);
|
|
854
|
-
this._deleteNestedValue(result, oldKey);
|
|
855
|
-
this._setNestedValue(result, newKey, value);
|
|
856
|
-
}
|
|
857
|
-
break;
|
|
858
|
-
case '$push':
|
|
859
|
-
for (const [key, value] of Object.entries(fields)) {
|
|
860
|
-
const current = this._getNestedValue(result, key);
|
|
861
|
-
const array = Array.isArray(current) ? [...current] : [];
|
|
862
|
-
if (typeof value === 'object' && value !== null && '$each' in value) {
|
|
863
|
-
const eachValue = value;
|
|
864
|
-
array.push(...eachValue.$each);
|
|
865
|
-
}
|
|
866
|
-
else {
|
|
867
|
-
array.push(value);
|
|
868
|
-
}
|
|
869
|
-
this._setNestedValue(result, key, array);
|
|
870
|
-
}
|
|
871
|
-
break;
|
|
872
|
-
case '$pull':
|
|
873
|
-
for (const [key, value] of Object.entries(fields)) {
|
|
874
|
-
const current = this._getNestedValue(result, key);
|
|
875
|
-
if (Array.isArray(current)) {
|
|
876
|
-
const newArray = current.filter(item => !this._valuesEqual(item, value));
|
|
877
|
-
this._setNestedValue(result, key, newArray);
|
|
878
|
-
}
|
|
879
|
-
}
|
|
880
|
-
break;
|
|
881
|
-
case '$pop':
|
|
882
|
-
for (const [key, value] of Object.entries(fields)) {
|
|
883
|
-
const current = this._getNestedValue(result, key);
|
|
884
|
-
if (Array.isArray(current)) {
|
|
885
|
-
const newArray = [...current];
|
|
886
|
-
if (value === 1) {
|
|
887
|
-
newArray.pop();
|
|
888
|
-
}
|
|
889
|
-
else if (value === -1) {
|
|
890
|
-
newArray.shift();
|
|
891
|
-
}
|
|
892
|
-
this._setNestedValue(result, key, newArray);
|
|
893
|
-
}
|
|
894
|
-
}
|
|
895
|
-
break;
|
|
896
|
-
case '$addToSet':
|
|
897
|
-
for (const [key, value] of Object.entries(fields)) {
|
|
898
|
-
const current = this._getNestedValue(result, key);
|
|
899
|
-
const array = Array.isArray(current) ? [...current] : [];
|
|
900
|
-
if (typeof value === 'object' && value !== null && '$each' in value) {
|
|
901
|
-
const eachValue = value;
|
|
902
|
-
for (const item of eachValue.$each) {
|
|
903
|
-
if (!array.some(existing => this._valuesEqual(existing, item))) {
|
|
904
|
-
array.push(item);
|
|
905
|
-
}
|
|
906
|
-
}
|
|
907
|
-
}
|
|
908
|
-
else if (!array.some(existing => this._valuesEqual(existing, value))) {
|
|
909
|
-
array.push(value);
|
|
910
|
-
}
|
|
911
|
-
this._setNestedValue(result, key, array);
|
|
912
|
-
}
|
|
913
|
-
break;
|
|
914
|
-
case '$currentDate':
|
|
915
|
-
for (const [key, value] of Object.entries(fields)) {
|
|
916
|
-
if (value === true || (typeof value === 'object' && value.$type === 'date')) {
|
|
917
|
-
this._setNestedValue(result, key, new Date());
|
|
918
|
-
}
|
|
919
|
-
else if (typeof value === 'object' && value.$type === 'timestamp') {
|
|
920
|
-
this._setNestedValue(result, key, Date.now());
|
|
921
|
-
}
|
|
922
|
-
}
|
|
923
|
-
break;
|
|
924
|
-
}
|
|
925
|
-
}
|
|
926
|
-
return result;
|
|
927
|
-
}
|
|
928
|
-
/**
|
|
929
|
-
* Set a nested value in an object
|
|
930
|
-
*/
|
|
931
|
-
_setNestedValue(obj, path, value) {
|
|
932
|
-
const parts = path.split('.');
|
|
933
|
-
let current = obj;
|
|
934
|
-
for (let i = 0; i < parts.length - 1; i++) {
|
|
935
|
-
const part = parts[i];
|
|
936
|
-
if (part === undefined)
|
|
937
|
-
continue;
|
|
938
|
-
if (current[part] === undefined || current[part] === null) {
|
|
939
|
-
current[part] = {};
|
|
940
|
-
}
|
|
941
|
-
current = current[part];
|
|
942
|
-
}
|
|
943
|
-
const lastPart = parts[parts.length - 1];
|
|
944
|
-
if (lastPart !== undefined) {
|
|
945
|
-
current[lastPart] = value;
|
|
946
|
-
}
|
|
947
|
-
}
|
|
948
|
-
/**
|
|
949
|
-
* Delete a nested value from an object
|
|
950
|
-
*/
|
|
951
|
-
_deleteNestedValue(obj, path) {
|
|
952
|
-
const parts = path.split('.');
|
|
953
|
-
let current = obj;
|
|
954
|
-
for (let i = 0; i < parts.length - 1; i++) {
|
|
955
|
-
const part = parts[i];
|
|
956
|
-
if (part === undefined)
|
|
957
|
-
continue;
|
|
958
|
-
if (current[part] === undefined || current[part] === null) {
|
|
959
|
-
return;
|
|
960
|
-
}
|
|
961
|
-
current = current[part];
|
|
962
|
-
}
|
|
963
|
-
const lastPart = parts[parts.length - 1];
|
|
964
|
-
if (lastPart !== undefined) {
|
|
965
|
-
delete current[lastPart];
|
|
966
|
-
}
|
|
967
|
-
}
|
|
968
|
-
/**
|
|
969
|
-
* Sort documents by the given sort specification
|
|
970
|
-
*/
|
|
971
|
-
_sortDocuments(docs, sort) {
|
|
972
|
-
return [...docs].sort((a, b) => {
|
|
973
|
-
for (const [key, direction] of Object.entries(sort)) {
|
|
974
|
-
const aValue = this._getNestedValue(a, key);
|
|
975
|
-
const bValue = this._getNestedValue(b, key);
|
|
976
|
-
let comparison = 0;
|
|
977
|
-
if (aValue === bValue) {
|
|
978
|
-
comparison = 0;
|
|
979
|
-
}
|
|
980
|
-
else if (aValue === null || aValue === undefined) {
|
|
981
|
-
comparison = -1;
|
|
982
|
-
}
|
|
983
|
-
else if (bValue === null || bValue === undefined) {
|
|
984
|
-
comparison = 1;
|
|
985
|
-
}
|
|
986
|
-
else if (typeof aValue === 'string' && typeof bValue === 'string') {
|
|
987
|
-
comparison = aValue.localeCompare(bValue);
|
|
988
|
-
}
|
|
989
|
-
else if (typeof aValue === 'number' && typeof bValue === 'number') {
|
|
990
|
-
comparison = aValue - bValue;
|
|
991
|
-
}
|
|
992
|
-
else {
|
|
993
|
-
comparison = String(aValue).localeCompare(String(bValue));
|
|
994
|
-
}
|
|
995
|
-
if (comparison !== 0) {
|
|
996
|
-
return comparison * direction;
|
|
997
|
-
}
|
|
998
|
-
}
|
|
999
|
-
return 0;
|
|
1000
|
-
});
|
|
1001
|
-
}
|
|
1002
|
-
/**
|
|
1003
|
-
* Apply projection to a document
|
|
1004
|
-
* @internal
|
|
1005
|
-
*/
|
|
1006
|
-
_applyProjection(doc, projection) {
|
|
1007
|
-
const hasInclusions = Object.values(projection).some(v => v === 1);
|
|
1008
|
-
const hasExclusions = Object.values(projection).some(v => v === 0);
|
|
1009
|
-
// Cannot mix inclusions and exclusions (except for _id)
|
|
1010
|
-
if (hasInclusions) {
|
|
1011
|
-
const result = {};
|
|
1012
|
-
// Always include _id unless explicitly excluded
|
|
1013
|
-
if (projection._id !== 0) {
|
|
1014
|
-
result._id = doc._id;
|
|
1015
|
-
}
|
|
1016
|
-
for (const [key, value] of Object.entries(projection)) {
|
|
1017
|
-
if (value === 1 && key !== '_id') {
|
|
1018
|
-
result[key] = this._getNestedValue(doc, key);
|
|
1019
|
-
}
|
|
1020
|
-
}
|
|
1021
|
-
return result;
|
|
1022
|
-
}
|
|
1023
|
-
else if (hasExclusions) {
|
|
1024
|
-
const result = { ...doc };
|
|
1025
|
-
for (const [key, value] of Object.entries(projection)) {
|
|
1026
|
-
if (value === 0) {
|
|
1027
|
-
delete result[key];
|
|
1028
|
-
}
|
|
1029
|
-
}
|
|
1030
|
-
return result;
|
|
1031
|
-
}
|
|
1032
|
-
return doc;
|
|
1033
|
-
}
|
|
1034
|
-
/**
|
|
1035
|
-
* Extract updated and removed fields from an update object
|
|
1036
|
-
* @internal
|
|
1037
|
-
*/
|
|
1038
|
-
_extractUpdateChanges(update) {
|
|
1039
|
-
const updateObj = update;
|
|
1040
|
-
const updatedFields = {};
|
|
1041
|
-
const removedFields = [];
|
|
1042
|
-
// Extract fields from $set
|
|
1043
|
-
if (updateObj.$set) {
|
|
1044
|
-
Object.assign(updatedFields, updateObj.$set);
|
|
1045
|
-
}
|
|
1046
|
-
// Extract fields from $unset
|
|
1047
|
-
if (updateObj.$unset) {
|
|
1048
|
-
removedFields.push(...Object.keys(updateObj.$unset));
|
|
1049
|
-
}
|
|
1050
|
-
// Extract fields from $inc, $mul, $min, $max (these set values)
|
|
1051
|
-
for (const op of ['$inc', '$mul', '$min', '$max']) {
|
|
1052
|
-
if (updateObj[op]) {
|
|
1053
|
-
for (const key of Object.keys(updateObj[op])) {
|
|
1054
|
-
updatedFields[key] = updateObj[op][key];
|
|
1055
|
-
}
|
|
1056
|
-
}
|
|
1057
|
-
}
|
|
1058
|
-
// Handle $push (updated fields)
|
|
1059
|
-
if (updateObj.$push) {
|
|
1060
|
-
for (const key of Object.keys(updateObj.$push)) {
|
|
1061
|
-
updatedFields[key] = updateObj.$push[key];
|
|
1062
|
-
}
|
|
1063
|
-
}
|
|
1064
|
-
// Handle $pull (updated fields)
|
|
1065
|
-
if (updateObj.$pull) {
|
|
1066
|
-
for (const key of Object.keys(updateObj.$pull)) {
|
|
1067
|
-
updatedFields[key] = updateObj.$pull[key];
|
|
1068
|
-
}
|
|
1069
|
-
}
|
|
1070
|
-
// Handle $addToSet (updated fields)
|
|
1071
|
-
if (updateObj.$addToSet) {
|
|
1072
|
-
for (const key of Object.keys(updateObj.$addToSet)) {
|
|
1073
|
-
updatedFields[key] = updateObj.$addToSet[key];
|
|
1074
|
-
}
|
|
1075
|
-
}
|
|
1076
|
-
return { updatedFields, removedFields };
|
|
1077
|
-
}
|
|
1078
|
-
/**
|
|
1079
|
-
* Execute an aggregation pipeline on the collection
|
|
1080
|
-
*
|
|
1081
|
-
* Returns an AggregationCursor that supports:
|
|
1082
|
-
* - Async iteration with `for await (const doc of cursor)`
|
|
1083
|
-
* - Converting to array with `await cursor.toArray()`
|
|
1084
|
-
* - forEach iteration with `await cursor.forEach(callback)`
|
|
1085
|
-
*
|
|
1086
|
-
* Supports async stages like $function and $lookup with pipeline.
|
|
1087
|
-
*
|
|
1088
|
-
* @param pipeline - Array of aggregation pipeline stages
|
|
1089
|
-
* @param options - Aggregation options
|
|
1090
|
-
* @returns AggregationCursor for iterating over results
|
|
1091
|
-
*
|
|
1092
|
-
* @example
|
|
1093
|
-
* ```typescript
|
|
1094
|
-
* // Using toArray
|
|
1095
|
-
* const results = await collection.aggregate([
|
|
1096
|
-
* { $match: { status: 'active' } },
|
|
1097
|
-
* { $group: { _id: '$category', count: { $sum: 1 } } }
|
|
1098
|
-
* ]).toArray()
|
|
1099
|
-
*
|
|
1100
|
-
* // Using async iterator
|
|
1101
|
-
* for await (const doc of collection.aggregate([
|
|
1102
|
-
* { $match: { status: 'active' } }
|
|
1103
|
-
* ])) {
|
|
1104
|
-
* console.log(doc)
|
|
1105
|
-
* }
|
|
1106
|
-
* ```
|
|
1107
|
-
*/
|
|
1108
|
-
aggregate(pipeline, options = {}) {
|
|
1109
|
-
// Create execution context for async stages
|
|
1110
|
-
const context = {
|
|
1111
|
-
collectionName: this._collectionName,
|
|
1112
|
-
lookupCollection: async (name) => {
|
|
1113
|
-
// Get documents from another collection for $lookup
|
|
1114
|
-
const targetCollection = this.database.collection(name);
|
|
1115
|
-
return targetCollection._findDocuments({});
|
|
1116
|
-
},
|
|
1117
|
-
functionExecutor: async (fn, doc) => {
|
|
1118
|
-
// Execute $function stage
|
|
1119
|
-
return this._executeFunctionStage(fn, doc);
|
|
1120
|
-
}
|
|
1121
|
-
};
|
|
1122
|
-
// Create fetch function that executes the pipeline
|
|
1123
|
-
const fetchFn = async () => {
|
|
1124
|
-
// Get all documents from collection
|
|
1125
|
-
const allDocs = this._findDocuments({});
|
|
1126
|
-
// Execute pipeline stages
|
|
1127
|
-
return this._executeAggregationPipeline(allDocs, pipeline);
|
|
1128
|
-
};
|
|
1129
|
-
return new AggregationCursor(pipeline, fetchFn, options, undefined, // No custom async executor - we handle in fetch
|
|
1130
|
-
context);
|
|
1131
|
-
}
|
|
1132
|
-
/**
|
|
1133
|
-
* Execute $function stage on a document
|
|
1134
|
-
* @internal
|
|
1135
|
-
*/
|
|
1136
|
-
async _executeFunctionStage(fn, doc) {
|
|
1137
|
-
let func;
|
|
1138
|
-
if (typeof fn.body === 'string') {
|
|
1139
|
-
// String function bodies require secure worker-loader execution
|
|
1140
|
-
throw new Error('$function requires worker_loaders binding. ' +
|
|
1141
|
-
'Add to wrangler.jsonc: "worker_loaders": [{ "binding": "LOADER" }]');
|
|
1142
|
-
}
|
|
1143
|
-
else {
|
|
1144
|
-
func = fn.body;
|
|
1145
|
-
}
|
|
1146
|
-
// Resolve args - replace field references with actual values
|
|
1147
|
-
const resolvedArgs = fn.args.map(arg => {
|
|
1148
|
-
if (typeof arg === 'string' && arg.startsWith('$')) {
|
|
1149
|
-
return this._getNestedValue(doc, arg.slice(1));
|
|
1150
|
-
}
|
|
1151
|
-
return arg;
|
|
1152
|
-
});
|
|
1153
|
-
// Execute function
|
|
1154
|
-
return func(...resolvedArgs);
|
|
1155
|
-
}
|
|
1156
|
-
/**
|
|
1157
|
-
* Execute aggregation pipeline on documents (in-memory implementation)
|
|
1158
|
-
* @internal
|
|
1159
|
-
*/
|
|
1160
|
-
_executeAggregationPipeline(documents, pipeline) {
|
|
1161
|
-
let results = documents.map(doc => ({ ...doc }));
|
|
1162
|
-
for (const stage of pipeline) {
|
|
1163
|
-
const stageType = Object.keys(stage)[0];
|
|
1164
|
-
if (stageType === undefined)
|
|
1165
|
-
continue;
|
|
1166
|
-
const stageValue = stage[stageType];
|
|
1167
|
-
switch (stageType) {
|
|
1168
|
-
case '$match':
|
|
1169
|
-
results = results.filter(doc => this._matchesFilter(doc, stageValue));
|
|
1170
|
-
break;
|
|
1171
|
-
case '$project':
|
|
1172
|
-
results = this._executeProjectStage(results, stageValue);
|
|
1173
|
-
break;
|
|
1174
|
-
case '$group':
|
|
1175
|
-
results = this._executeGroupStage(results, stageValue);
|
|
1176
|
-
break;
|
|
1177
|
-
case '$sort':
|
|
1178
|
-
results = this._executeSortStage(results, stageValue);
|
|
1179
|
-
break;
|
|
1180
|
-
case '$limit':
|
|
1181
|
-
results = results.slice(0, stageValue);
|
|
1182
|
-
break;
|
|
1183
|
-
case '$skip':
|
|
1184
|
-
results = results.slice(stageValue);
|
|
1185
|
-
break;
|
|
1186
|
-
case '$count':
|
|
1187
|
-
results = [{ [stageValue]: results.length }];
|
|
1188
|
-
break;
|
|
1189
|
-
case '$unwind':
|
|
1190
|
-
results = this._executeUnwindStage(results, stageValue);
|
|
1191
|
-
break;
|
|
1192
|
-
case '$addFields':
|
|
1193
|
-
case '$set':
|
|
1194
|
-
results = this._executeAddFieldsStage(results, stageValue);
|
|
1195
|
-
break;
|
|
1196
|
-
case '$lookup':
|
|
1197
|
-
results = this._executeLookupStage(results, stageValue);
|
|
1198
|
-
break;
|
|
1199
|
-
default:
|
|
1200
|
-
// Unsupported stage - pass through
|
|
1201
|
-
break;
|
|
1202
|
-
}
|
|
1203
|
-
}
|
|
1204
|
-
return results;
|
|
1205
|
-
}
|
|
1206
|
-
/**
|
|
1207
|
-
* Execute $project stage
|
|
1208
|
-
* @internal
|
|
1209
|
-
*/
|
|
1210
|
-
_executeProjectStage(documents, projection) {
|
|
1211
|
-
// Check if we have inclusions or expressions (expressions count as inclusions)
|
|
1212
|
-
const hasInclusion = Object.entries(projection).some(([key, v]) => {
|
|
1213
|
-
if (key === '_id')
|
|
1214
|
-
return false; // _id: 0 doesn't count
|
|
1215
|
-
return v === 1 ||
|
|
1216
|
-
(typeof v === 'string' && v.startsWith('$')) ||
|
|
1217
|
-
(typeof v === 'object' && v !== null);
|
|
1218
|
-
});
|
|
1219
|
-
const excludeId = projection._id === 0;
|
|
1220
|
-
return documents.map(doc => {
|
|
1221
|
-
const result = {};
|
|
1222
|
-
if (hasInclusion) {
|
|
1223
|
-
// Inclusion mode
|
|
1224
|
-
if (!excludeId && '_id' in doc) {
|
|
1225
|
-
result._id = doc._id;
|
|
1226
|
-
}
|
|
1227
|
-
for (const [key, value] of Object.entries(projection)) {
|
|
1228
|
-
if (key === '_id' && value === 0)
|
|
1229
|
-
continue;
|
|
1230
|
-
if (key === '_id' && value === 1) {
|
|
1231
|
-
result._id = doc._id;
|
|
1232
|
-
continue;
|
|
1233
|
-
}
|
|
1234
|
-
if (value === 1) {
|
|
1235
|
-
result[key] = this._getNestedValue(doc, key);
|
|
1236
|
-
}
|
|
1237
|
-
else if (typeof value === 'string' && value.startsWith('$')) {
|
|
1238
|
-
result[key] = this._getNestedValue(doc, value.slice(1));
|
|
1239
|
-
}
|
|
1240
|
-
else if (typeof value === 'object' && value !== null) {
|
|
1241
|
-
result[key] = this._evaluateExpression(doc, value);
|
|
1242
|
-
}
|
|
1243
|
-
}
|
|
1244
|
-
}
|
|
1245
|
-
else {
|
|
1246
|
-
// Exclusion mode
|
|
1247
|
-
for (const [key, val] of Object.entries(doc)) {
|
|
1248
|
-
if (projection[key] === 0)
|
|
1249
|
-
continue;
|
|
1250
|
-
result[key] = val;
|
|
1251
|
-
}
|
|
1252
|
-
}
|
|
1253
|
-
return result;
|
|
1254
|
-
});
|
|
1255
|
-
}
|
|
1256
|
-
/**
|
|
1257
|
-
* Execute $group stage
|
|
1258
|
-
* @internal
|
|
1259
|
-
*/
|
|
1260
|
-
_executeGroupStage(documents, groupSpec) {
|
|
1261
|
-
const groups = new Map();
|
|
1262
|
-
for (const doc of documents) {
|
|
1263
|
-
// Compute group key
|
|
1264
|
-
let groupKey;
|
|
1265
|
-
const idSpec = groupSpec._id;
|
|
1266
|
-
if (idSpec === null) {
|
|
1267
|
-
groupKey = '__all__';
|
|
1268
|
-
}
|
|
1269
|
-
else if (typeof idSpec === 'string' && idSpec.startsWith('$')) {
|
|
1270
|
-
groupKey = String(this._getNestedValue(doc, idSpec.slice(1)));
|
|
1271
|
-
}
|
|
1272
|
-
else if (typeof idSpec === 'object' && idSpec !== null) {
|
|
1273
|
-
const keyObj = {};
|
|
1274
|
-
for (const [k, v] of Object.entries(idSpec)) {
|
|
1275
|
-
if (typeof v === 'string' && v.startsWith('$')) {
|
|
1276
|
-
keyObj[k] = this._getNestedValue(doc, v.slice(1));
|
|
1277
|
-
}
|
|
1278
|
-
else {
|
|
1279
|
-
keyObj[k] = v;
|
|
1280
|
-
}
|
|
1281
|
-
}
|
|
1282
|
-
groupKey = JSON.stringify(keyObj);
|
|
1283
|
-
}
|
|
1284
|
-
else {
|
|
1285
|
-
groupKey = String(idSpec);
|
|
1286
|
-
}
|
|
1287
|
-
if (!groups.has(groupKey)) {
|
|
1288
|
-
// Initialize group
|
|
1289
|
-
let idValue;
|
|
1290
|
-
if (idSpec === null) {
|
|
1291
|
-
idValue = null;
|
|
1292
|
-
}
|
|
1293
|
-
else if (typeof idSpec === 'string' && idSpec.startsWith('$')) {
|
|
1294
|
-
idValue = this._getNestedValue(doc, idSpec.slice(1));
|
|
1295
|
-
}
|
|
1296
|
-
else if (typeof idSpec === 'object' && idSpec !== null) {
|
|
1297
|
-
idValue = {};
|
|
1298
|
-
for (const [k, v] of Object.entries(idSpec)) {
|
|
1299
|
-
if (typeof v === 'string' && v.startsWith('$')) {
|
|
1300
|
-
idValue[k] = this._getNestedValue(doc, v.slice(1));
|
|
1301
|
-
}
|
|
1302
|
-
else {
|
|
1303
|
-
idValue[k] = v;
|
|
1304
|
-
}
|
|
1305
|
-
}
|
|
1306
|
-
}
|
|
1307
|
-
else {
|
|
1308
|
-
idValue = idSpec;
|
|
1309
|
-
}
|
|
1310
|
-
groups.set(groupKey, { docs: [], result: { _id: idValue } });
|
|
1311
|
-
}
|
|
1312
|
-
groups.get(groupKey).docs.push(doc);
|
|
1313
|
-
}
|
|
1314
|
-
// Apply accumulators
|
|
1315
|
-
const results = [];
|
|
1316
|
-
for (const { docs, result } of groups.values()) {
|
|
1317
|
-
for (const [key, accumulator] of Object.entries(groupSpec)) {
|
|
1318
|
-
if (key === '_id')
|
|
1319
|
-
continue;
|
|
1320
|
-
if (typeof accumulator === 'object' && accumulator !== null) {
|
|
1321
|
-
const accObj = accumulator;
|
|
1322
|
-
const accType = Object.keys(accObj)[0];
|
|
1323
|
-
if (accType === undefined)
|
|
1324
|
-
continue;
|
|
1325
|
-
const accValue = accObj[accType];
|
|
1326
|
-
switch (accType) {
|
|
1327
|
-
case '$sum':
|
|
1328
|
-
if (accValue === 1) {
|
|
1329
|
-
result[key] = docs.length;
|
|
1330
|
-
}
|
|
1331
|
-
else if (typeof accValue === 'string' && accValue.startsWith('$')) {
|
|
1332
|
-
result[key] = docs.reduce((sum, d) => {
|
|
1333
|
-
const val = this._getNestedValue(d, accValue.slice(1));
|
|
1334
|
-
return sum + (typeof val === 'number' ? val : 0);
|
|
1335
|
-
}, 0);
|
|
1336
|
-
}
|
|
1337
|
-
break;
|
|
1338
|
-
case '$avg':
|
|
1339
|
-
if (typeof accValue === 'string' && accValue.startsWith('$')) {
|
|
1340
|
-
const sum = docs.reduce((s, d) => {
|
|
1341
|
-
const val = this._getNestedValue(d, accValue.slice(1));
|
|
1342
|
-
return s + (typeof val === 'number' ? val : 0);
|
|
1343
|
-
}, 0);
|
|
1344
|
-
result[key] = docs.length > 0 ? sum / docs.length : null;
|
|
1345
|
-
}
|
|
1346
|
-
break;
|
|
1347
|
-
case '$min':
|
|
1348
|
-
if (typeof accValue === 'string' && accValue.startsWith('$')) {
|
|
1349
|
-
const values = docs.map(d => this._getNestedValue(d, accValue.slice(1)));
|
|
1350
|
-
result[key] = Math.min(...values.filter(v => typeof v === 'number'));
|
|
1351
|
-
}
|
|
1352
|
-
break;
|
|
1353
|
-
case '$max':
|
|
1354
|
-
if (typeof accValue === 'string' && accValue.startsWith('$')) {
|
|
1355
|
-
const values = docs.map(d => this._getNestedValue(d, accValue.slice(1)));
|
|
1356
|
-
result[key] = Math.max(...values.filter(v => typeof v === 'number'));
|
|
1357
|
-
}
|
|
1358
|
-
break;
|
|
1359
|
-
case '$count':
|
|
1360
|
-
result[key] = docs.length;
|
|
1361
|
-
break;
|
|
1362
|
-
case '$first':
|
|
1363
|
-
if (typeof accValue === 'string' && accValue.startsWith('$')) {
|
|
1364
|
-
const firstDoc = docs[0];
|
|
1365
|
-
result[key] = firstDoc !== undefined ? this._getNestedValue(firstDoc, accValue.slice(1)) : null;
|
|
1366
|
-
}
|
|
1367
|
-
break;
|
|
1368
|
-
case '$last':
|
|
1369
|
-
if (typeof accValue === 'string' && accValue.startsWith('$')) {
|
|
1370
|
-
const lastDoc = docs[docs.length - 1];
|
|
1371
|
-
result[key] = lastDoc !== undefined ? this._getNestedValue(lastDoc, accValue.slice(1)) : null;
|
|
1372
|
-
}
|
|
1373
|
-
break;
|
|
1374
|
-
case '$push':
|
|
1375
|
-
if (typeof accValue === 'string' && accValue.startsWith('$')) {
|
|
1376
|
-
result[key] = docs.map(d => this._getNestedValue(d, accValue.slice(1)));
|
|
1377
|
-
}
|
|
1378
|
-
break;
|
|
1379
|
-
case '$addToSet':
|
|
1380
|
-
if (typeof accValue === 'string' && accValue.startsWith('$')) {
|
|
1381
|
-
const set = new Set();
|
|
1382
|
-
for (const d of docs) {
|
|
1383
|
-
set.add(JSON.stringify(this._getNestedValue(d, accValue.slice(1))));
|
|
1384
|
-
}
|
|
1385
|
-
result[key] = Array.from(set).map(s => JSON.parse(s));
|
|
1386
|
-
}
|
|
1387
|
-
break;
|
|
1388
|
-
}
|
|
1389
|
-
}
|
|
1390
|
-
}
|
|
1391
|
-
results.push(result);
|
|
1392
|
-
}
|
|
1393
|
-
return results;
|
|
1394
|
-
}
|
|
1395
|
-
/**
|
|
1396
|
-
* Execute $sort stage
|
|
1397
|
-
* @internal
|
|
1398
|
-
*/
|
|
1399
|
-
_executeSortStage(documents, sortSpec) {
|
|
1400
|
-
return [...documents].sort((a, b) => {
|
|
1401
|
-
for (const [field, direction] of Object.entries(sortSpec)) {
|
|
1402
|
-
const aVal = this._getNestedValue(a, field);
|
|
1403
|
-
const bVal = this._getNestedValue(b, field);
|
|
1404
|
-
let comparison = 0;
|
|
1405
|
-
if (aVal === bVal) {
|
|
1406
|
-
comparison = 0;
|
|
1407
|
-
}
|
|
1408
|
-
else if (aVal === null || aVal === undefined) {
|
|
1409
|
-
comparison = -1;
|
|
1410
|
-
}
|
|
1411
|
-
else if (bVal === null || bVal === undefined) {
|
|
1412
|
-
comparison = 1;
|
|
1413
|
-
}
|
|
1414
|
-
else if (typeof aVal === 'string' && typeof bVal === 'string') {
|
|
1415
|
-
comparison = aVal.localeCompare(bVal);
|
|
1416
|
-
}
|
|
1417
|
-
else {
|
|
1418
|
-
comparison = aVal - bVal;
|
|
1419
|
-
}
|
|
1420
|
-
if (comparison !== 0) {
|
|
1421
|
-
return comparison * direction;
|
|
1422
|
-
}
|
|
1423
|
-
}
|
|
1424
|
-
return 0;
|
|
1425
|
-
});
|
|
1426
|
-
}
|
|
1427
|
-
/**
|
|
1428
|
-
* Execute $unwind stage
|
|
1429
|
-
* @internal
|
|
1430
|
-
*/
|
|
1431
|
-
_executeUnwindStage(documents, unwindSpec) {
|
|
1432
|
-
const path = typeof unwindSpec === 'string' ? unwindSpec : unwindSpec.path;
|
|
1433
|
-
const preserveNull = typeof unwindSpec === 'object' && unwindSpec.preserveNullAndEmptyArrays === true;
|
|
1434
|
-
const fieldPath = path.startsWith('$') ? path.slice(1) : path;
|
|
1435
|
-
const results = [];
|
|
1436
|
-
for (const doc of documents) {
|
|
1437
|
-
const arrayValue = this._getNestedValue(doc, fieldPath);
|
|
1438
|
-
if (Array.isArray(arrayValue) && arrayValue.length > 0) {
|
|
1439
|
-
for (const item of arrayValue) {
|
|
1440
|
-
const newDoc = { ...doc };
|
|
1441
|
-
this._setNestedValue(newDoc, fieldPath, item);
|
|
1442
|
-
results.push(newDoc);
|
|
1443
|
-
}
|
|
1444
|
-
}
|
|
1445
|
-
else if (preserveNull) {
|
|
1446
|
-
results.push({ ...doc });
|
|
1447
|
-
}
|
|
1448
|
-
}
|
|
1449
|
-
return results;
|
|
1450
|
-
}
|
|
1451
|
-
/**
|
|
1452
|
-
* Execute $addFields/$set stage
|
|
1453
|
-
* @internal
|
|
1454
|
-
*/
|
|
1455
|
-
_executeAddFieldsStage(documents, fieldsSpec) {
|
|
1456
|
-
return documents.map(doc => {
|
|
1457
|
-
const result = { ...doc };
|
|
1458
|
-
for (const [field, value] of Object.entries(fieldsSpec)) {
|
|
1459
|
-
if (typeof value === 'string' && value.startsWith('$')) {
|
|
1460
|
-
result[field] = this._getNestedValue(doc, value.slice(1));
|
|
1461
|
-
}
|
|
1462
|
-
else if (typeof value === 'object' && value !== null) {
|
|
1463
|
-
result[field] = this._evaluateExpression(doc, value);
|
|
1464
|
-
}
|
|
1465
|
-
else {
|
|
1466
|
-
result[field] = value;
|
|
1467
|
-
}
|
|
1468
|
-
}
|
|
1469
|
-
return result;
|
|
1470
|
-
});
|
|
1471
|
-
}
|
|
1472
|
-
/**
|
|
1473
|
-
* Execute $lookup stage
|
|
1474
|
-
* @internal
|
|
1475
|
-
*/
|
|
1476
|
-
_executeLookupStage(documents, lookupSpec) {
|
|
1477
|
-
const targetCollection = this.database.collection(lookupSpec.from);
|
|
1478
|
-
const targetDocs = targetCollection._findDocuments({});
|
|
1479
|
-
return documents.map(doc => {
|
|
1480
|
-
const result = { ...doc };
|
|
1481
|
-
if (lookupSpec.localField && lookupSpec.foreignField) {
|
|
1482
|
-
const localValue = this._getNestedValue(doc, lookupSpec.localField);
|
|
1483
|
-
const matched = targetDocs.filter(targetDoc => {
|
|
1484
|
-
const foreignValue = this._getNestedValue(targetDoc, lookupSpec.foreignField);
|
|
1485
|
-
return this._valuesEqual(localValue, foreignValue);
|
|
1486
|
-
});
|
|
1487
|
-
result[lookupSpec.as] = matched;
|
|
1488
|
-
}
|
|
1489
|
-
else {
|
|
1490
|
-
result[lookupSpec.as] = [];
|
|
1491
|
-
}
|
|
1492
|
-
return result;
|
|
1493
|
-
});
|
|
1494
|
-
}
|
|
1495
|
-
/**
|
|
1496
|
-
* Evaluate an expression (simplified)
|
|
1497
|
-
* @internal
|
|
1498
|
-
*/
|
|
1499
|
-
_evaluateExpression(doc, expr) {
|
|
1500
|
-
if (expr === null || typeof expr !== 'object') {
|
|
1501
|
-
return expr;
|
|
1502
|
-
}
|
|
1503
|
-
const exprObj = expr;
|
|
1504
|
-
const operator = Object.keys(exprObj)[0];
|
|
1505
|
-
if (operator === undefined)
|
|
1506
|
-
return expr;
|
|
1507
|
-
const operand = exprObj[operator];
|
|
1508
|
-
switch (operator) {
|
|
1509
|
-
case '$concat':
|
|
1510
|
-
if (Array.isArray(operand)) {
|
|
1511
|
-
return operand.map(item => {
|
|
1512
|
-
if (typeof item === 'string' && item.startsWith('$')) {
|
|
1513
|
-
return String(this._getNestedValue(doc, item.slice(1)) ?? '');
|
|
1514
|
-
}
|
|
1515
|
-
return String(item);
|
|
1516
|
-
}).join('');
|
|
1517
|
-
}
|
|
1518
|
-
break;
|
|
1519
|
-
case '$add':
|
|
1520
|
-
if (Array.isArray(operand)) {
|
|
1521
|
-
return operand.reduce((sum, item) => {
|
|
1522
|
-
if (typeof item === 'string' && item.startsWith('$')) {
|
|
1523
|
-
return sum + (Number(this._getNestedValue(doc, item.slice(1))) || 0);
|
|
1524
|
-
}
|
|
1525
|
-
return sum + (Number(item) || 0);
|
|
1526
|
-
}, 0);
|
|
1527
|
-
}
|
|
1528
|
-
break;
|
|
1529
|
-
case '$subtract':
|
|
1530
|
-
if (Array.isArray(operand) && operand.length === 2) {
|
|
1531
|
-
const a = typeof operand[0] === 'string' && operand[0].startsWith('$')
|
|
1532
|
-
? Number(this._getNestedValue(doc, operand[0].slice(1)))
|
|
1533
|
-
: Number(operand[0]);
|
|
1534
|
-
const b = typeof operand[1] === 'string' && operand[1].startsWith('$')
|
|
1535
|
-
? Number(this._getNestedValue(doc, operand[1].slice(1)))
|
|
1536
|
-
: Number(operand[1]);
|
|
1537
|
-
return a - b;
|
|
1538
|
-
}
|
|
1539
|
-
break;
|
|
1540
|
-
case '$multiply':
|
|
1541
|
-
if (Array.isArray(operand)) {
|
|
1542
|
-
return operand.reduce((product, item) => {
|
|
1543
|
-
if (typeof item === 'string' && item.startsWith('$')) {
|
|
1544
|
-
return product * (Number(this._getNestedValue(doc, item.slice(1))) || 0);
|
|
1545
|
-
}
|
|
1546
|
-
return product * (Number(item) || 0);
|
|
1547
|
-
}, 1);
|
|
1548
|
-
}
|
|
1549
|
-
break;
|
|
1550
|
-
case '$divide':
|
|
1551
|
-
if (Array.isArray(operand) && operand.length === 2) {
|
|
1552
|
-
const a = typeof operand[0] === 'string' && operand[0].startsWith('$')
|
|
1553
|
-
? Number(this._getNestedValue(doc, operand[0].slice(1)))
|
|
1554
|
-
: Number(operand[0]);
|
|
1555
|
-
const b = typeof operand[1] === 'string' && operand[1].startsWith('$')
|
|
1556
|
-
? Number(this._getNestedValue(doc, operand[1].slice(1)))
|
|
1557
|
-
: Number(operand[1]);
|
|
1558
|
-
return b !== 0 ? a / b : null;
|
|
1559
|
-
}
|
|
1560
|
-
break;
|
|
1561
|
-
case '$cond':
|
|
1562
|
-
if (typeof operand === 'object' && operand !== null) {
|
|
1563
|
-
const cond = operand;
|
|
1564
|
-
const condition = this._evaluateCondition(doc, cond.if);
|
|
1565
|
-
return condition
|
|
1566
|
-
? this._evaluateExpression(doc, cond.then)
|
|
1567
|
-
: this._evaluateExpression(doc, cond.else);
|
|
1568
|
-
}
|
|
1569
|
-
break;
|
|
1570
|
-
case '$ifNull':
|
|
1571
|
-
if (Array.isArray(operand) && operand.length === 2) {
|
|
1572
|
-
const value = typeof operand[0] === 'string' && operand[0].startsWith('$')
|
|
1573
|
-
? this._getNestedValue(doc, operand[0].slice(1))
|
|
1574
|
-
: operand[0];
|
|
1575
|
-
return value ?? operand[1];
|
|
1576
|
-
}
|
|
1577
|
-
break;
|
|
1578
|
-
}
|
|
1579
|
-
return expr;
|
|
1580
|
-
}
|
|
1581
|
-
/**
|
|
1582
|
-
* Evaluate a condition
|
|
1583
|
-
* @internal
|
|
1584
|
-
*/
|
|
1585
|
-
_evaluateCondition(doc, condition) {
|
|
1586
|
-
if (typeof condition !== 'object' || condition === null) {
|
|
1587
|
-
return Boolean(condition);
|
|
1588
|
-
}
|
|
1589
|
-
const condObj = condition;
|
|
1590
|
-
const operator = Object.keys(condObj)[0];
|
|
1591
|
-
if (operator === undefined)
|
|
1592
|
-
return true;
|
|
1593
|
-
const operand = condObj[operator];
|
|
1594
|
-
switch (operator) {
|
|
1595
|
-
case '$eq':
|
|
1596
|
-
return this._compareExprValues(doc, operand[0], operand[1]) === 0;
|
|
1597
|
-
case '$ne':
|
|
1598
|
-
return this._compareExprValues(doc, operand[0], operand[1]) !== 0;
|
|
1599
|
-
case '$gt':
|
|
1600
|
-
return this._compareExprValues(doc, operand[0], operand[1]) > 0;
|
|
1601
|
-
case '$gte':
|
|
1602
|
-
return this._compareExprValues(doc, operand[0], operand[1]) >= 0;
|
|
1603
|
-
case '$lt':
|
|
1604
|
-
return this._compareExprValues(doc, operand[0], operand[1]) < 0;
|
|
1605
|
-
case '$lte':
|
|
1606
|
-
return this._compareExprValues(doc, operand[0], operand[1]) <= 0;
|
|
1607
|
-
case '$and':
|
|
1608
|
-
return operand.every(c => this._evaluateCondition(doc, c));
|
|
1609
|
-
case '$or':
|
|
1610
|
-
return operand.some(c => this._evaluateCondition(doc, c));
|
|
1611
|
-
default:
|
|
1612
|
-
return true;
|
|
1613
|
-
}
|
|
1614
|
-
}
|
|
1615
|
-
/**
|
|
1616
|
-
* Compare two expression values
|
|
1617
|
-
* @internal
|
|
1618
|
-
*/
|
|
1619
|
-
_compareExprValues(doc, a, b) {
|
|
1620
|
-
const resolveValue = (val) => {
|
|
1621
|
-
if (typeof val === 'string' && val.startsWith('$')) {
|
|
1622
|
-
return this._getNestedValue(doc, val.slice(1));
|
|
1623
|
-
}
|
|
1624
|
-
return val;
|
|
1625
|
-
};
|
|
1626
|
-
const aVal = resolveValue(a);
|
|
1627
|
-
const bVal = resolveValue(b);
|
|
1628
|
-
if (aVal === bVal)
|
|
1629
|
-
return 0;
|
|
1630
|
-
if (aVal === null || aVal === undefined)
|
|
1631
|
-
return -1;
|
|
1632
|
-
if (bVal === null || bVal === undefined)
|
|
1633
|
-
return 1;
|
|
1634
|
-
if (typeof aVal === 'number' && typeof bVal === 'number') {
|
|
1635
|
-
return aVal - bVal;
|
|
1636
|
-
}
|
|
1637
|
-
return String(aVal).localeCompare(String(bVal));
|
|
1638
|
-
}
|
|
1639
|
-
}
|
|
1640
|
-
export default MongoCollection;
|
|
1641
|
-
//# sourceMappingURL=mongo-collection.js.map
|