Skip to content

Commit ab6584a

Browse files
committed
generalize Mongo.PipelineQuery to handle collection agnostic queries
1 parent d66a088 commit ab6584a

22 files changed

+162
-60
lines changed

Package.resolved

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Package.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ let package:Package = .init(
8989
.package(url: "https://github.com/tayloraswift/swift-json", .upToNextMinor(
9090
from: "1.1.2")),
9191
.package(url: "https://github.com/tayloraswift/swift-mongodb", .upToNextMinor(
92-
from: "0.29.2")),
92+
from: "0.29.3")),
9393
.package(url: "https://github.com/tayloraswift/swift-png", .upToNextMinor(
9494
from: "4.4.9")),
9595
.package(url: "https://github.com/tayloraswift/swift-ucf", .upToNextMinor(

Sources/UnidocDB/Editions/Unidoc.EditionPlacementQuery.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,10 @@ extension Unidoc
2020
}
2121
extension Unidoc.EditionPlacementQuery:Mongo.PipelineQuery
2222
{
23-
typealias CollectionOrigin = Unidoc.DB.Editions
2423
typealias Iteration = Mongo.Single<Unidoc.EditionPlacement>
2524

2625
var collation:Mongo.Collation { .simple }
26+
var from:Mongo.Collection? { Unidoc.DB.Editions.name }
2727
var hint:Mongo.CollectionIndex? { nil }
2828

2929
func build(pipeline:inout Mongo.PipelineEncoder)

Sources/UnidocDB/Packages/Unidoc.AliasQuery.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,10 @@ extension Unidoc
2929
}
3030
extension Unidoc.AliasQuery:Mongo.PipelineQuery
3131
{
32-
typealias CollectionOrigin = Aliases
3332
typealias Iteration = Mongo.Single<Never>
3433

3534
var collation:Mongo.Collation { .simple }
35+
var from:Mongo.Collection? { Aliases.name }
3636
var hint:Mongo.CollectionIndex? { nil }
3737

3838
func build(pipeline:inout Mongo.PipelineEncoder)

Sources/UnidocDB/Packages/Unidoc.AutoincrementQuery.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,10 @@ extension Unidoc
2121
}
2222
extension Unidoc.AutoincrementQuery:Mongo.PipelineQuery
2323
{
24-
typealias CollectionOrigin = Aliases
2524
typealias Iteration = Mongo.Single<Unidoc.Autoincrement<Targets.Element>>
2625

2726
var collation:Mongo.Collation { .simple }
27+
var from:Mongo.Collection? { Aliases.name }
2828
var hint:Mongo.CollectionIndex? { nil }
2929

3030
func build(pipeline:inout Mongo.PipelineEncoder)

Sources/UnidocDB/Sitemaps/Unidoc.SitemapIndexQuery.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@ extension Unidoc
1010
}
1111
extension Unidoc.SitemapIndexQuery:Mongo.PipelineQuery
1212
{
13-
typealias CollectionOrigin = Unidoc.DB.Sitemaps
1413
typealias Iteration = Mongo.Cursor<Unidoc.SitemapIndexEntry>
1514

1615
var collation:Mongo.Collation { .simple }
16+
var from:Mongo.Collection? { Unidoc.DB.Sitemaps.name }
1717
var hint:Mongo.CollectionIndex? { nil }
1818

1919
func build(pipeline:inout Mongo.PipelineEncoder)

Sources/UnidocDB/Snapshots/Unidoc.PinDependenciesQuery.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,10 @@ extension Unidoc.PinDependenciesQuery
4949
}
5050
extension Unidoc.PinDependenciesQuery:Mongo.PipelineQuery
5151
{
52-
typealias CollectionOrigin = Unidoc.DB.PackageAliases
5352
typealias Iteration = Mongo.SingleBatch<Symbol.PackageDependency<Unidoc.EditionMetadata>>
5453

5554
var collation:Mongo.Collation { .simple }
55+
var from:Mongo.Collection? { Unidoc.DB.PackageAliases.name }
5656
var hint:Mongo.CollectionIndex? { nil }
5757

5858
func build(pipeline:inout Mongo.PipelineEncoder)
@@ -75,6 +75,8 @@ extension Unidoc.PinDependenciesQuery:Mongo.PipelineQuery
7575

7676
// Map the coordinates back to the patch versions associated with the original
7777
// packages.
78+
//
79+
// https://www.mongodb.com/docs/manual/reference/operator/aggregation/documents/#use-a--documents-stage-in-a--lookup-stage
7880
pipeline[stage: .lookup]
7981
{
8082
$0[.foreignField] = Symbol.PackageDependency<PatchVersion>[.package]
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import BSON
2+
import MongoQL
3+
import SymbolGraphs
4+
import Symbols
5+
6+
extension Unidoc.ActivityQuery
7+
{
8+
@frozen public
9+
struct Featured<Article>:Sendable where Article:Sendable
10+
{
11+
public
12+
let package:Symbol.Package
13+
public
14+
let article:Article
15+
16+
@inlinable public
17+
init(package:Symbol.Package, article:Article)
18+
{
19+
self.package = package
20+
self.article = article
21+
}
22+
}
23+
}
24+
extension Unidoc.ActivityQuery.Featured:Mongo.MasterCodingModel
25+
{
26+
@frozen public
27+
enum CodingKey:String, Sendable
28+
{
29+
case package = "P"
30+
case article = "A"
31+
}
32+
}
33+
extension Unidoc.ActivityQuery.Featured:BSONDocumentEncodable, BSONEncodable
34+
where Article:BSONEncodable
35+
{
36+
public
37+
func encode(to bson:inout BSON.DocumentEncoder<CodingKey>)
38+
{
39+
bson[.package] = self.package
40+
bson[.article] = self.article
41+
}
42+
}
43+
extension Unidoc.ActivityQuery.Featured:BSONDocumentDecodable, BSONDecodable
44+
where Article:BSONDecodable
45+
{
46+
@inlinable public
47+
init(bson:BSON.DocumentDecoder<CodingKey>) throws
48+
{
49+
self.init(
50+
package: try bson[.package].decode(),
51+
article: try bson[.article].decode())
52+
}
53+
}

Sources/UnidocQueries/Activity/Unidoc.ActivityQuery.Output.swift

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,18 @@ extension Unidoc.ActivityQuery
1212
let repo:[Unidoc.DB.RepoFeed.Activity]
1313
public
1414
let docs:[Unidoc.DB.DocsFeed.Activity<Unidoc.VolumeMetadata>]
15+
public
16+
var featured:[Featured<Unidoc.AnyVertex>]
1517

16-
@inlinable internal
18+
@inlinable
1719
init(
1820
repo:[Unidoc.DB.RepoFeed.Activity],
19-
docs:[Unidoc.DB.DocsFeed.Activity<Unidoc.VolumeMetadata>])
21+
docs:[Unidoc.DB.DocsFeed.Activity<Unidoc.VolumeMetadata>],
22+
featured:[Featured<Unidoc.AnyVertex>])
2023
{
2124
self.repo = repo
2225
self.docs = docs
26+
self.featured = featured
2327
}
2428
}
2529
}
@@ -30,13 +34,17 @@ extension Unidoc.ActivityQuery.Output:Mongo.MasterCodingModel
3034
{
3135
case repo = "R"
3236
case docs = "D"
37+
case featured = "F"
3338
}
3439
}
3540
extension Unidoc.ActivityQuery.Output:BSONDocumentDecodable
3641
{
3742
@inlinable public
3843
init(bson:BSON.DocumentDecoder<CodingKey>) throws
3944
{
40-
self.init(repo: try bson[.repo].decode(), docs: try bson[.docs].decode())
45+
self.init(
46+
repo: try bson[.repo].decode(),
47+
docs: try bson[.docs].decode(),
48+
featured: try bson[.featured].decode())
4149
}
4250
}

Sources/UnidocQueries/Activity/Unidoc.ActivityQuery.swift

Lines changed: 56 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1+
import BSON
12
import MongoDB
23
import MongoQL
4+
import Symbols
35
import Unidoc
46
import UnidocDB
57
import UnidocRecords
@@ -19,57 +21,91 @@ extension Unidoc
1921
}
2022
}
2123
}
24+
extension Unidoc.ActivityQuery
25+
{
26+
private
27+
static var featured:[Featured<Unidoc.Stem>]
28+
{
29+
[
30+
]
31+
}
32+
}
2233
extension Unidoc.ActivityQuery:Mongo.PipelineQuery
2334
{
24-
public
25-
typealias CollectionOrigin = Unidoc.DB.DocsFeed
2635
public
2736
typealias Iteration = Mongo.Single<Output>
2837

38+
/// This must be ``Mongo.Collation/casefolding`` for the featured article lookup to use
39+
/// the index.
40+
@inlinable public
41+
var collation:Mongo.Collation { .casefolding }
2942
@inlinable public
30-
var collation:Mongo.Collation { .simple }
43+
var from:Mongo.Collection? { nil }
3144
@inlinable public
3245
var hint:Mongo.CollectionIndex? { nil }
3346

3447
public
3548
func build(pipeline:inout Mongo.PipelineEncoder)
3649
{
37-
// Cannot use $natural sort in an aggregation pipeline.
38-
pipeline[stage: .sort,
39-
using: Unidoc.DB.DocsFeed.Activity<Unidoc.Edition>.CodingKey.self]
40-
{
41-
$0[.id] = (-)
42-
}
43-
44-
pipeline[stage: .limit] = self.limit
45-
46-
pipeline[stage: .facet, using: Output.CodingKey.self]
50+
pipeline[stage: .documents] = [[:] as [BSON.Key: Never]]
51+
pipeline[stage: .lookup]
4752
{
48-
$0[.docs]
53+
$0[.pipeline]
4954
{
55+
$0[stage: .documents] = Self.featured
5056
$0[stage: .lookup]
5157
{
52-
let id:Mongo.Variable<Unidoc.Edition> = "id"
58+
let trunk:Mongo.Variable<Symbol.Package> = "trunk"
59+
let stem:Mongo.Variable<Unidoc.Stem> = "stem"
5360

54-
$0[.from] = Unidoc.DB.Volumes.name
61+
$0[.from] = Unidoc.DB.Vertices.name
5562
$0[.let]
5663
{
57-
$0[let: id] = Unidoc.DB.DocsFeed.Activity<Unidoc.Edition>[.volume]
64+
$0[let: trunk] = Featured<Unidoc.Stem>[.package]
65+
$0[let: stem] = Featured<Unidoc.Stem>[.article]
5866
}
5967
$0[.pipeline]
6068
{
6169
$0[stage: .match]
6270
{
63-
$0[.expr] { $0[.eq] = (Unidoc.VolumeMetadata[.id], id) }
71+
$0[.and]
72+
{
73+
$0 { $0[Unidoc.AnyVertex[.linkable]] = true }
74+
$0 { $0[.expr] { $0[.eq] = (Unidoc.AnyVertex[.stem], stem) } }
75+
$0 { $0[.expr] { $0[.eq] = (Unidoc.AnyVertex[.trunk], trunk) } }
76+
}
6477
}
65-
66-
$0[stage: .project] = Unidoc.VolumeMetadata.NameFields.init()
6778
}
79+
$0[.as] = Featured<Unidoc.AnyVertex>[.article]
80+
}
81+
$0[stage: .unwind] = Featured<Unidoc.AnyVertex>[.article]
82+
}
83+
$0[.as] = Output[.featured]
84+
}
85+
86+
pipeline[stage: .lookup]
87+
{
88+
$0[.from] = Unidoc.DB.DocsFeed.name
89+
$0[.pipeline]
90+
{
91+
// Cannot use $natural sort in an aggregation pipeline.
92+
$0[stage: .sort,
93+
using: Unidoc.DB.DocsFeed.Activity<Unidoc.Edition>.CodingKey.self]
94+
{
95+
$0[.id] = (-)
96+
}
97+
$0[stage: .limit] = self.limit
98+
$0[stage: .lookup]
99+
{
100+
$0[.from] = Unidoc.DB.Volumes.name
101+
$0[.localField] = Unidoc.DB.DocsFeed.Activity<Unidoc.Edition>[.volume]
102+
$0[.foreignField] = Unidoc.VolumeMetadata[.id]
68103
$0[.as] = Unidoc.DB.DocsFeed.Activity<Unidoc.VolumeMetadata>[.volume]
69104
}
70105

71106
$0[stage: .unwind] = Unidoc.DB.DocsFeed.Activity<Unidoc.VolumeMetadata>[.volume]
72107
}
108+
$0[.as] = Output[.docs]
73109
}
74110

75111
pipeline[stage: .lookup]

Sources/UnidocQueries/Activity/Unidoc.PackagesCrawledQuery.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,14 @@ extension Unidoc
2020
}
2121
extension Unidoc.PackagesCrawledQuery:Mongo.PipelineQuery
2222
{
23-
public
24-
typealias CollectionOrigin = Unidoc.DB.CrawlingWindows
2523
public
2624
typealias Iteration = Mongo.SingleBatch<Date>
2725

2826
@inlinable public
2927
var collation:Mongo.Collation { .simple }
3028
@inlinable public
29+
var from:Mongo.Collection? { Unidoc.DB.CrawlingWindows.name }
30+
@inlinable public
3131
var hint:Mongo.CollectionIndex? { nil }
3232

3333
public

Sources/UnidocQueries/Packages/Unidoc.AliasingQuery.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ extension Unidoc
1111
protocol AliasingQuery<CollectionOrigin, CollectionTarget>:Mongo.PipelineQuery
1212
where CollectionOrigin.Element:Mongo.MasterCodingModel<AliasKey>
1313
{
14+
associatedtype CollectionOrigin:Mongo.CollectionModel
1415
associatedtype CollectionTarget:Mongo.CollectionModel
1516

1617
/// The field to store the target document (a `CollectionTarget.Element`) in.
@@ -27,6 +28,8 @@ extension Unidoc.AliasingQuery
2728
@inlinable public
2829
var collation:Mongo.Collation { .simple }
2930
@inlinable public
31+
var from:Mongo.Collection? { CollectionOrigin.name }
32+
@inlinable public
3033
var hint:Mongo.CollectionIndex? { nil }
3134

3235
public

Sources/UnidocQueries/Packages/Unidoc.PackagesQuery.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,14 @@ extension Unidoc.PackagesQuery<Unidoc.PackageCreated>
2828
}
2929
extension Unidoc.PackagesQuery:Mongo.PipelineQuery
3030
{
31-
public
32-
typealias CollectionOrigin = Unidoc.DB.Packages
3331
public
3432
typealias Iteration = Mongo.SingleBatch<Unidoc.EditionOutput>
3533

3634
@inlinable public
3735
var collation:Mongo.Collation { .simple }
3836
@inlinable public
37+
var from:Mongo.Collection? { Unidoc.DB.Packages.name }
38+
@inlinable public
3939
var hint:Mongo.CollectionIndex? { self.package.hint }
4040

4141
public

Sources/UnidocQueries/Search/Unidoc.TextResourceQuery.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ extension Unidoc.TextResourceQuery:Mongo.PipelineQuery
3434
@inlinable public
3535
var collation:Mongo.Collation { .casefolding }
3636
@inlinable public
37+
var from:Mongo.Collection? { CollectionOrigin.name }
38+
@inlinable public
3739
var hint:Mongo.CollectionIndex? { nil }
3840

3941
public

Sources/UnidocQueries/Users/Unidoc.UserAccountQuery.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,14 @@ extension Unidoc
1919
}
2020
extension Unidoc.UserAccountQuery:Mongo.PipelineQuery
2121
{
22-
public
23-
typealias CollectionOrigin = Unidoc.DB.Users
2422
public
2523
typealias Iteration = Mongo.Single<Output>
2624

2725
@inlinable public
2826
var collation:Mongo.Collation { .simple }
2927
@inlinable public
28+
var from:Mongo.Collection? { Unidoc.DB.Users.name }
29+
@inlinable public
3030
var hint:Mongo.CollectionIndex? { nil }
3131

3232
public

0 commit comments

Comments
 (0)