Skip to content

Commit f587059

Browse files
committed
api docs for many-to-many counts
1 parent 4dd21fa commit f587059

File tree

4 files changed

+126
-3
lines changed

4 files changed

+126
-3
lines changed

constellation/src/server/filters.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,7 @@ pub fn to_browseable(s: &str) -> askama::Result<Option<String>> {
2222
pub fn human_number(n: &u64) -> askama::Result<String> {
2323
Ok(n.to_formatted_string(&Locale::en))
2424
}
25+
26+
pub fn to_u64(n: usize) -> askama::Result<u64> {
27+
Ok(n as u64)
28+
}

constellation/templates/get-many-to-many-counts.html.j2

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,62 @@
22
{% import "try-it-macros.html.j2" as try_it %}
33

44
{% block title %}Many to Many counts{% endblock %}
5-
{% block description %}All {{ query.source }} records with links to {{ query.subject }}{% endblock %}
5+
{% block description %}Counts of many-to-many {{ query.source }} join records with links to {{ query.subject }} and a secondary target at {{ query.path_to_other }}{% endblock %}
66

77
{% block content %}
88

9-
(todo)
9+
{% call try_it::get_many_to_many_counts(
10+
query.subject,
11+
query.source,
12+
query.path_to_other,
13+
query.did,
14+
query.other_subject,
15+
query.limit,
16+
) %}
17+
18+
<h2>
19+
Many-to-many links to <code>{{ query.subject }}</code> joining through <code>{{ query.path_to_other }}</code>
20+
{% if let Some(browseable_uri) = query.subject|to_browseable %}
21+
<small style="font-weight: normal; font-size: 1rem"><a href="{{ browseable_uri }}">browse record</a></small>
22+
{% endif %}
23+
</h2>
24+
25+
<p><strong>{% if cursor.is_some() || query.cursor.is_some() %}more than {% endif %}{{ counts_by_other_subject.len()|to_u64|human_number }} joins</strong> <code>{{ query.source }}→{{ query.path_to_other }}</code></p>
26+
27+
<ul>
28+
<li>See direct backlinks at <code>/xrpc/blue.microcosm.links.getBacklinks</code>: <a href="/xrpc/blue.microcosm.links.getBacklinks?subject={{ query.subject|urlencode }}&source={{ query.source|urlencode }}">/xrpc/blue.microcosm.links.getBacklinks?subject={{ query.subject }}&source={{ query.source }}</a></li>
29+
<li>See all links to this target at <code>/links/all</code>: <a href="/links/all?target={{ query.subject|urlencode }}">/links/all?target={{ query.subject }}</a></li>
30+
</ul>
31+
32+
<h3>Counts by other subject:</h3>
33+
34+
{% for counts in counts_by_other_subject %}
35+
<pre style="display: block; margin: 1em 2em" class="code"><strong>Joined subject</strong>: {{ counts.subject }}
36+
<strong>Joining records</strong>: {{ counts.total }}
37+
<strong>Unique joiner ids</strong>: {{ counts.distinct }}
38+
-> {% if let Some(browseable_uri) = counts.subject|to_browseable -%}
39+
<a href="{{ browseable_uri }}">browse record</a>
40+
{%- endif %}</pre>
41+
{% endfor %}
42+
43+
{% if let Some(c) = cursor %}
44+
<form method="get" action="/xrpc/blue.microcosm.links.getManyToManyCounts">
45+
<input type="hidden" name="subject" value="{{ query.subject }}" />
46+
<input type="hidden" name="source" value="{{ query.source }}" />
47+
<input type="hidden" name="pathToOther" value="{{ query.path_to_other }}" />
48+
{% for did in query.did %}
49+
<input type="hidden" name="did" value="{{ did }}" />
50+
{% endfor %}
51+
{% for otherSubject in query.other_subject %}
52+
<input type="hidden" name="otherSubject" value="{{ otherSubject }}" />
53+
{% endfor %}
54+
<input type="hidden" name="limit" value="{{ query.limit }}" />
55+
<input type="hidden" name="cursor" value={{ c|json|safe }} />
56+
<button type="submit">next page&hellip;</button>
57+
</form>
58+
{% else %}
59+
<button disabled><em>end of results</em></button>
60+
{% endif %}
1061

1162
<details>
1263
<summary>Raw JSON response</summary>

constellation/templates/hello.html.j2

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,32 @@
5555
{% call try_it::get_backlinks("at://did:plc:a4pqq234yw7fqbddawjo7y35/app.bsky.feed.post/3m237ilwc372e", "app.bsky.feed.like:subject.uri", [""], 16) %}
5656

5757

58+
<h3 class="route"><code>GET /xrpc/blue.microcosm.links.getManyToManyCounts</code></h3>
59+
60+
<p>TODO: description</p>
61+
62+
<h4>Query parameters:</h4>
63+
64+
<ul>
65+
<li><p><code>subject</code>: required, must url-encode. Example: <code>at://did:plc:vc7f4oafdgxsihk4cry2xpze/app.bsky.feed.post/3lgwdn7vd722r</code></p></li>
66+
<li><p><code>source</code>: required. Example: <code>app.bsky.feed.like:subject.uri</code></p></li>
67+
<li><p><code>pathToOther</code>: required. Path to the secondary link in the many-to-many record. Example: <code>otherThing.uri</code></p></li>
68+
<li><p><code>did</code>: optional, filter links to those from specific users. Include multiple times to filter by multiple users. Example: <code>did=did:plc:vc7f4oafdgxsihk4cry2xpze&did=did:plc:vc7f4oafdgxsihk4cry2xpze</code></p></li>
69+
<li><p><code>otherSubject</code>: optional, filter secondary links to specific subjects. Include multiple times to filter by multiple users. Example: <code>at://did:plc:vc7f4oafdgxsihk4cry2xpze/app.bsky.feed.post/3lgwdn7vd722r</code></p></li>
70+
<li><p><code>limit</code>: optional. Default: <code>16</code>. Maximum: <code>100</code></p></li>
71+
</ul>
72+
73+
<p style="margin-bottom: 0"><strong>Try it:</strong></p>
74+
{% call try_it::get_many_to_many_counts(
75+
"at://did:plc:a4pqq234yw7fqbddawjo7y35/app.bsky.feed.post/3m237ilwc372e",
76+
"app.bsky.feed.like:subject.uri",
77+
"otherThing.uri",
78+
[""],
79+
[""],
80+
16,
81+
) %}
82+
83+
5884
<h3 class="route"><code>GET /links</code></h3>
5985

6086
<p>A list of records linking to a target.</p>

constellation/templates/try-it-macros.html.j2

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{% macro get_backlinks(subject, source, dids, limit) %}
22
<form method="get" action="/xrpc/blue.microcosm.links.getBacklinks">
3-
<pre class="code"><strong>GET</strong> /links
3+
<pre class="code"><strong>GET</strong> /xrpc/blue.microcosm.links.getBacklinks
44
?subject= <input type="text" name="subject" value="{{ subject }}" placeholder="at-uri, did, uri..." />
55
&source= <input type="text" name="source" value="{{ source }}" placeholder="app.bsky.feed.like:subject.uri" />
66
{%- for did in dids %}{% if !did.is_empty() %}
@@ -24,6 +24,48 @@
2424
</script>
2525
{% endmacro %}
2626

27+
{% macro get_many_to_many_counts(subject, source, pathToOther, dids, otherSubjects, limit) %}
28+
<form method="get" action="/xrpc/blue.microcosm.links.getManyToManyCounts">
29+
<pre class="code"><strong>GET</strong> /xrpc/blue.microcosm.links.getManyToManyCounts
30+
?subject= <input type="text" name="subject" value="{{ subject }}" placeholder="at-uri, did, uri..." />
31+
&source= <input type="text" name="source" value="{{ source }}" placeholder="app.bsky.feed.like:subject.uri" />
32+
&pathToOther= <input type="text" name="pathToOther" value="{{ pathToOther }}" placeholder="otherThing.uri" />
33+
{%- for did in dids %}{% if !did.is_empty() %}
34+
&did= <input type="text" name="did" value="{{ did }}" placeholder="did:plc:..." />{% endif %}{% endfor %}
35+
<span id="m2m-subject-placeholder"></span> <button id="m2m-add-subject">+ other subject filter</button>
36+
{%- for otherSubject in otherSubjects %}{% if !otherSubject.is_empty() %}
37+
&otherSubject= <input type="text" name="did" value="{{ otherSubject }}" placeholder="at-uri, did, uri..." />{% endif %}{% endfor %}
38+
<span id="m2m-did-placeholder"></span> <button id="m2m-add-did">+ did filter</button>
39+
&limit= <input type="number" name="limit" value="{{ limit }}" max="100" placeholder="100" /> <button type="submit">get links</button></pre>
40+
</form>
41+
<script>
42+
const m2mAddDidButton = document.getElementById('m2m-add-did');
43+
const m2mDidPlaceholder = document.getElementById('m2m-did-placeholder');
44+
m2mAddDidButton.addEventListener('click', e => {
45+
e.preventDefault();
46+
const i = document.createElement('input');
47+
i.placeholder = 'did:plc:...';
48+
i.name = "did"
49+
const p = m2mAddDidButton.parentNode;
50+
p.insertBefore(document.createTextNode('&did= '), m2mDidPlaceholder);
51+
p.insertBefore(i, m2mDidPlaceholder);
52+
p.insertBefore(document.createTextNode('\n '), m2mDidPlaceholder);
53+
});
54+
const m2mAddSubjectButton = document.getElementById('m2m-add-subject');
55+
const m2mSubjectPlaceholder = document.getElementById('m2m-subject-placeholder');
56+
m2mAddSubjectButton.addEventListener('click', e => {
57+
e.preventDefault();
58+
const i = document.createElement('input');
59+
i.placeholder = 'at-uri, did, uri...';
60+
i.name = "otherSubject"
61+
const p = m2mAddSubjectButton.parentNode;
62+
p.insertBefore(document.createTextNode('&otherSubject= '), m2mSubjectPlaceholder);
63+
p.insertBefore(i, m2mSubjectPlaceholder);
64+
p.insertBefore(document.createTextNode('\n '), m2mSubjectPlaceholder);
65+
});
66+
</script>
67+
{% endmacro %}
68+
2769
{% macro links(target, collection, path, dids, limit) %}
2870
<form method="get" action="/links">
2971
<pre class="code"><strong>GET</strong> /links

0 commit comments

Comments
 (0)