11namespace SqlStreamStore . HAL
22{
3+ using System ;
4+ using System . Collections . Generic ;
5+ using System . Runtime . InteropServices ;
36 using Halcyon . HAL ;
47
58 internal static class Links
69 {
7- public static Link Find ( string href ) => new Link ( Constants . Relations . Find , href , "Find a Stream" , replaceParameters : false ) ;
8- public static Link Index ( string href ) => new Link ( Constants . Relations . Index , href , "Index" , replaceParameters : false ) ;
10+ public static Link Find ( string href ) =>
11+ new Link ( Constants . Relations . Find , href , "Find a Stream" , replaceParameters : false ) ;
12+
13+ public static Link Index ( string href ) =>
14+ new Link ( Constants . Relations . Index , href , "Index" , replaceParameters : false ) ;
15+ }
16+
17+ internal static class LinkExtensions
18+ {
19+ public static TheLinks Index ( this TheLinks links ) =>
20+ links . Add ( Constants . Relations . Index , string . Empty , "Index" ) ;
21+
22+ public static TheLinks Find ( this TheLinks links )
23+ => links . Add ( Constants . Relations . Find , "stream/{streamId}" , "Find a Stream" ) ;
24+ }
25+
26+ internal class TheLinks
27+ {
28+ private readonly List < ( string rel , string href , string title ) > _links ;
29+ private readonly string _relativePathToRoot ;
30+
31+ public static TheLinks RootedAt ( string relativePathToRoot ) => new TheLinks ( relativePathToRoot ) ;
32+
33+ private TheLinks ( string relativePathToRoot )
34+ {
35+ if ( ! string . IsNullOrEmpty ( relativePathToRoot ) )
36+ {
37+ if ( ! relativePathToRoot . StartsWith ( ".." ) )
38+ {
39+ throw new ArgumentException ( "Non-empty relative path to root must start with '..'" ,
40+ nameof ( relativePathToRoot ) ) ;
41+ }
42+
43+ if ( ! relativePathToRoot . EndsWith ( "/" ) )
44+ {
45+ throw new ArgumentException ( "Non-empty relative path to root must end with '/'" ,
46+ nameof ( relativePathToRoot ) ) ;
47+ }
48+ }
49+
50+ _relativePathToRoot = relativePathToRoot ?? string . Empty ;
51+ _links = new List < ( string rel , string href , string title ) > ( ) ;
52+ }
53+
54+ public TheLinks Add ( string rel , string href , string title = null )
55+ {
56+ if ( rel == null )
57+ throw new ArgumentNullException ( nameof ( rel ) ) ;
58+ if ( href == null )
59+ throw new ArgumentNullException ( nameof ( href ) ) ;
60+
61+ _links . Add ( ( rel , href , title ) ) ;
62+ return this ;
63+ }
64+
65+ public TheLinks Self ( )
66+ {
67+ var link = _links [ _links . Count - 1 ] ;
68+
69+ return Add ( Constants . Relations . Self , link . href , link . title ) ;
70+ }
71+
72+ public TheLinks AddSelf ( string rel , string href , string title = null )
73+ => Add ( rel , href , title )
74+ . Add ( Constants . Relations . Self , href , title ) ;
75+
76+ public TheLinks Self ( string rel )
77+ {
78+ return this ;
79+ }
80+
81+ public Link [ ] ToHalLinks ( )
82+ {
83+ var links = new Link [ _links . Count ] ;
84+
85+ for ( var i = 0 ; i < _links . Count ; i ++ )
86+ {
87+ var ( rel , href , title ) = _links [ i ] ;
88+ var resolvedHref = $ "{ _relativePathToRoot } { href } ";
89+
90+ links [ i ] = new Link ( rel , resolvedHref , title , replaceParameters : false ) ;
91+ }
92+
93+ return links ;
94+ }
95+
96+ public static implicit operator Link [ ] ( TheLinks theLinks ) => theLinks . ToHalLinks ( ) ;
997 }
1098}
0 commit comments