Skip to content

Commit 67a04eb

Browse files
committed
simplify DB schema by encoding unconditional conformances separately from conditional conformances
1 parent 781284a commit 67a04eb

10 files changed

+75
-121
lines changed
Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,57 @@
1+
import Signatures
12
import UnidocRecords
23

34
extension Unidoc
45
{
56
struct Conformers:Identifiable
67
{
78
let id:LinkerIndex<Self>
8-
var list:[ConformingType]
99

1010
private
11-
init(id:LinkerIndex<Self>, list:[ConformingType])
11+
var unconditional:[Unidoc.Scalar]
12+
private
13+
var conditional:[ConformingType]
14+
15+
init(id:LinkerIndex<Self>)
1216
{
1317
self.id = id
14-
self.list = list
18+
self.unconditional = []
19+
self.conditional = []
1520
}
1621
}
1722
}
23+
extension Unidoc.Conformers
24+
{
25+
mutating
26+
func append(conformer type:Unidoc.Scalar,
27+
where constraints:[GenericConstraint<Unidoc.Scalar?>])
28+
{
29+
constraints.isEmpty
30+
? self.unconditional.append(type)
31+
: self.conditional.append(.init(id: type, where: constraints))
32+
}
33+
}
1834
extension Unidoc.Conformers:Unidoc.LinkerIndexable
1935
{
2036
typealias Signature = Unidoc.ConformanceSignature
2137

2238
static
2339
var type:Unidoc.GroupType { .conformers }
2440

25-
init(id:Unidoc.LinkerIndex<Self>)
41+
var isEmpty:Bool
2642
{
27-
self.init(id: id, list: [])
43+
self.unconditional.isEmpty && self.conditional.isEmpty
2844
}
2945

30-
var isEmpty:Bool { self.list.isEmpty }
31-
46+
__consuming
3247
func assemble(signature:Unidoc.ConformanceSignature,
3348
with linker:borrowing Unidoc.Linker) -> Unidoc.ConformerGroup
3449
{
3550
.init(id: self.id.in(linker.current.id),
3651
culture: linker.current.id + signature.culture,
3752
scope: signature.conformance,
38-
types: self.list) // do we need to sort this?
53+
unconditional: self.unconditional,
54+
conditional: self.conditional)
55+
// do we need to sort this?
3956
}
4057
}

Sources/UnidocLinker/Sema/Unidoc.Extension.swift

Lines changed: 8 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -23,24 +23,17 @@ extension Unidoc
2323
var overview:Unidoc.Passage?
2424
var details:Unidoc.Passage?
2525

26-
private
27-
init(id:LinkerIndex<Self>,
28-
conformances:[Unidoc.Scalar],
29-
features:[Unidoc.Scalar],
30-
nested:[Unidoc.Scalar],
31-
subforms:[Unidoc.Scalar],
32-
overview:Unidoc.Passage? ,
33-
details:Unidoc.Passage? )
26+
init(id:LinkerIndex<Self>)
3427
{
3528
self.id = id
3629

37-
self.conformances = conformances
38-
self.features = features
39-
self.nested = nested
40-
self.subforms = subforms
30+
self.conformances = []
31+
self.features = []
32+
self.nested = []
33+
self.subforms = []
4134

42-
self.overview = overview
43-
self.details = details
35+
self.overview = nil
36+
self.details = nil
4437
}
4538
}
4639
}
@@ -51,17 +44,6 @@ extension Unidoc.Extension:Unidoc.LinkerIndexable
5144
static
5245
var type:Unidoc.GroupType { .extension }
5346

54-
init(id:Unidoc.LinkerIndex<Self>)
55-
{
56-
self.init(id: id,
57-
conformances: [],
58-
features: [],
59-
nested: [],
60-
subforms: [],
61-
overview: nil,
62-
details: nil)
63-
}
64-
6547
var isEmpty:Bool
6648
{
6749
self.conformances.isEmpty &&
@@ -72,6 +54,7 @@ extension Unidoc.Extension:Unidoc.LinkerIndexable
7254
self.details == nil
7355
}
7456

57+
__consuming
7558
func assemble(signature:Unidoc.ExtensionSignature,
7659
with linker:borrowing Unidoc.Linker) -> Unidoc.ExtensionGroup
7760
{

Sources/UnidocLinker/Sema/Unidoc.Linker.Table.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,8 @@ extension Unidoc.Linker.Table<Unidoc.Conformers>
7272
{
7373
for condition:Unidoc.ExtensionConditions in conditions
7474
{
75-
self[.conforms(to: p, in: condition.culture)].list.append(.init(id: type,
76-
where: condition.constraints))
75+
self[.conforms(to: p, in: condition.culture)].append(conformer: type,
76+
where: condition.constraints)
7777
}
7878
}
7979
}

Sources/UnidocLinker/Sema/Unidoc.LinkerIndexable.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,6 @@ protocol _UnidocLinkerIndexable:Identifiable<Unidoc.LinkerIndex<Self>>
1414

1515
var isEmpty:Bool { get }
1616

17+
consuming
1718
func assemble(signature:Signature, with linker:borrowing Unidoc.Linker) -> Assembled
1819
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import MongoQL
2+
3+
extension Unidoc.ConformingType:MongoMasterCodingModel
4+
{
5+
}

Sources/UnidocQueries/Volumes/Unidoc.ConformingType.Conditional (ext).swift

Lines changed: 0 additions & 5 deletions
This file was deleted.

Sources/UnidocRecords/Volumes/Groups/Unidoc.AnyGroup.swift

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -66,9 +66,12 @@ extension Unidoc.AnyGroup
6666
/// which are, of course, scalars.
6767
case members = "t"
6868

69+
/// Optional and appears in ``ConformingTypesGroup`` only.
70+
/// The field contains a list of scalars.
71+
case unconditional = "u"
6972
/// Optional and appears in ``ConformingTypesGroup`` only.
7073
/// The field contains a list of conforming types, which contain scalars.
71-
case types = "k"
74+
case conditional = "k"
7275

7376
/// Contains a list of precomputed zones, as MongoDB cannot easily
7477
/// convert scalars to zones. This field will be computed and
@@ -119,11 +122,12 @@ extension Unidoc.AnyGroup:BSONDocumentEncodable
119122
bson[.culture] = self.culture
120123
bson[.scope] = self.scope
121124

122-
// This is the only array field and there is no reason why it would ever be empty.
123-
bson[.types] = self.types
125+
bson[.unconditional] = self.unconditional.isEmpty ? nil : self.unconditional
126+
bson[.conditional] = self.conditional.isEmpty ? nil : self.conditional
124127

125128
zones.update(with: self.culture.edition)
126-
zones.update(with: self.types)
129+
zones.update(with: self.unconditional)
130+
zones.update(with: self.conditional)
127131

128132
case .extension(let self):
129133
bson[.constraints] = self.constraints.isEmpty ? nil : self.constraints
@@ -186,7 +190,8 @@ extension Unidoc.AnyGroup:BSONDocumentDecodable
186190
self = .conformers(.init(id: id,
187191
culture: try bson[.culture].decode(),
188192
scope: try bson[.scope].decode(),
189-
types: try bson[.types].decode()))
193+
unconditional: try bson[.unconditional]?.decode() ?? [],
194+
conditional: try bson[.conditional]?.decode() ?? []))
190195

191196
case .extension?:
192197
self = .extension(.init(id: id,

Sources/UnidocRecords/Volumes/Groups/Unidoc.ConformerGroup.swift

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,22 @@ extension Unidoc
1414
let scope:Scalar
1515

1616
public
17-
var types:[ConformingType]
17+
var unconditional:[Unidoc.Scalar]
18+
public
19+
var conditional:[ConformingType]
1820

1921
@inlinable public
20-
init(id:Group, culture:Scalar, scope:Scalar, types:[ConformingType] = [])
22+
init(id:Group,
23+
culture:Scalar,
24+
scope:Scalar,
25+
unconditional:[Unidoc.Scalar] = [],
26+
conditional:[ConformingType] = [])
2127
{
2228
self.id = id
2329
self.culture = culture
2430
self.scope = scope
25-
self.types = types
31+
self.unconditional = unconditional
32+
self.conditional = conditional
2633
}
2734
}
2835
}

Sources/UnidocRecords/Volumes/Groups/Unidoc.ConformingType.Conditional.swift

Lines changed: 0 additions & 48 deletions
This file was deleted.
Lines changed: 14 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import BSON
22
import Signatures
3+
import SymbolGraphs
34

45
extension Unidoc
56
{
@@ -21,40 +22,28 @@ extension Unidoc
2122
}
2223
extension Unidoc.ConformingType
2324
{
24-
@inlinable
25-
var conditional:Conditional?
25+
@frozen public
26+
enum CodingKey:String, Sendable
2627
{
27-
self.constraints.isEmpty ? nil : .init(id: self.id, where: self.constraints)
28+
case id = "i"
29+
// Non-optional, because we expect to encode unconditional conformances separately.
30+
case constraints = "g"
2831
}
2932
}
30-
extension Unidoc.ConformingType:BSONEncodable
33+
extension Unidoc.ConformingType:BSONDocumentEncodable
3134
{
32-
@inlinable public
33-
func encode(to field:inout BSON.FieldEncoder)
35+
public
36+
func encode(to bson:inout BSON.DocumentEncoder<CodingKey>)
3437
{
35-
if let conditional:Conditional = self.conditional
36-
{
37-
conditional.encode(to: &field)
38-
}
39-
else
40-
{
41-
self.id.encode(to: &field)
42-
}
38+
bson[.id] = self.id
39+
bson[.constraints] = self.constraints
4340
}
4441
}
45-
extension Unidoc.ConformingType:BSONDecodable
42+
extension Unidoc.ConformingType:BSONDocumentDecodable
4643
{
4744
@inlinable public
48-
init(bson:BSON.AnyValue<some RandomAccessCollection<UInt8>>) throws
45+
init(bson:BSON.DocumentDecoder<CodingKey, some RandomAccessCollection<UInt8>>) throws
4946
{
50-
if case .id(let id) = bson
51-
{
52-
self.init(id: Unidoc.Scalar.init(id))
53-
}
54-
else
55-
{
56-
let conditional:Conditional = try .init(bson: bson)
57-
self.init(id: conditional.id, where: conditional.constraints)
58-
}
47+
self.init(id: try bson[.id].decode(), where: try bson[.constraints].decode())
5948
}
6049
}

0 commit comments

Comments
 (0)