Skip to content

Commit

Permalink
quote aggs, list quotes (#2658)
Browse files Browse the repository at this point in the history
* add quote count to post_agg, add getPostQuotes

rework schema

rework schema

add getPostQuotes to api

use posts

use posts

codegen

use items instead of quotes

codegen

add getPostQuotes

add quoteCount to response

update lexicon for postview

increment post ags

add quote to post aggs

add quote interface

oops

add quote table migration

* update

* bufgen

* update params

* update to use v2

* logs

* rm comment

* pass cursor

* add index

* Update packages/bsky/src/data-plane/server/db/migrations/20240723T220703655Z-quotes.ts

Co-authored-by: devin ivy <devinivy@gmail.com>

* only if its a post

* tests

* Discard changes to packages/bsky/tests/views/posts.test.ts

* fix client call

* Include new quotes agg in test expectation

* Use new API for headers

* Update packages/bsky/src/data-plane/server/indexing/plugins/post.ts

Co-authored-by: devin ivy <devinivy@gmail.com>

* revert rm

* rm timeout

* cursor test

* Changeset

* Remove pds specific bump

---------

Co-authored-by: devin ivy <devinivy@gmail.com>
Co-authored-by: Eric Bailey <git@esb.lol>
  • Loading branch information
3 people authored Aug 21, 2024
1 parent 922b2e8 commit 2a0c088
Show file tree
Hide file tree
Showing 54 changed files with 1,817 additions and 2 deletions.
6 changes: 6 additions & 0 deletions .changeset/cyan-ladybugs-dance.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@atproto/bsky": patch
"@atproto/api": patch
---

Adds `app.bsky.feed.getQuotes` lexicon and handlers
1 change: 1 addition & 0 deletions lexicons/app/bsky/feed/defs.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"replyCount": { "type": "integer" },
"repostCount": { "type": "integer" },
"likeCount": { "type": "integer" },
"quoteCount": { "type": "integer" },
"indexedAt": { "type": "string", "format": "datetime" },
"viewer": { "type": "ref", "ref": "#viewerState" },
"labels": {
Expand Down
52 changes: 52 additions & 0 deletions lexicons/app/bsky/feed/getQuotes.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
{
"lexicon": 1,
"id": "app.bsky.feed.getQuotes",
"defs": {
"main": {
"type": "query",
"description": "Get a list of quotes for a given post.",
"parameters": {
"type": "params",
"required": ["uri"],
"properties": {
"uri": {
"type": "string",
"format": "at-uri",
"description": "Reference (AT-URI) of post record"
},
"cid": {
"type": "string",
"format": "cid",
"description": "If supplied, filters to quotes of specific version (by CID) of the post record."
},
"limit": {
"type": "integer",
"minimum": 1,
"maximum": 100,
"default": 50
},
"cursor": { "type": "string" }
}
},
"output": {
"encoding": "application/json",
"schema": {
"type": "object",
"required": ["uri", "posts"],
"properties": {
"uri": { "type": "string", "format": "at-uri" },
"cid": { "type": "string", "format": "cid" },
"cursor": { "type": "string" },
"posts": {
"type": "array",
"items": {
"type": "ref",
"ref": "app.bsky.feed.defs#postView"
}
}
}
}
}
}
}
}
13 changes: 13 additions & 0 deletions packages/api/src/client/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ import * as AppBskyFeedGetLikes from './types/app/bsky/feed/getLikes'
import * as AppBskyFeedGetListFeed from './types/app/bsky/feed/getListFeed'
import * as AppBskyFeedGetPostThread from './types/app/bsky/feed/getPostThread'
import * as AppBskyFeedGetPosts from './types/app/bsky/feed/getPosts'
import * as AppBskyFeedGetQuotes from './types/app/bsky/feed/getQuotes'
import * as AppBskyFeedGetRepostedBy from './types/app/bsky/feed/getRepostedBy'
import * as AppBskyFeedGetSuggestedFeeds from './types/app/bsky/feed/getSuggestedFeeds'
import * as AppBskyFeedGetTimeline from './types/app/bsky/feed/getTimeline'
Expand Down Expand Up @@ -307,6 +308,7 @@ export * as AppBskyFeedGetLikes from './types/app/bsky/feed/getLikes'
export * as AppBskyFeedGetListFeed from './types/app/bsky/feed/getListFeed'
export * as AppBskyFeedGetPostThread from './types/app/bsky/feed/getPostThread'
export * as AppBskyFeedGetPosts from './types/app/bsky/feed/getPosts'
export * as AppBskyFeedGetQuotes from './types/app/bsky/feed/getQuotes'
export * as AppBskyFeedGetRepostedBy from './types/app/bsky/feed/getRepostedBy'
export * as AppBskyFeedGetSuggestedFeeds from './types/app/bsky/feed/getSuggestedFeeds'
export * as AppBskyFeedGetTimeline from './types/app/bsky/feed/getTimeline'
Expand Down Expand Up @@ -1739,6 +1741,17 @@ export class AppBskyFeedNS {
return this._client.call('app.bsky.feed.getPosts', params, undefined, opts)
}

getQuotes(
params?: AppBskyFeedGetQuotes.QueryParams,
opts?: AppBskyFeedGetQuotes.CallOptions,
): Promise<AppBskyFeedGetQuotes.Response> {
return this._client
.call('app.bsky.feed.getQuotes', params, undefined, opts)
.catch((e) => {
throw AppBskyFeedGetQuotes.toKnownErr(e)
})
}

getRepostedBy(
params?: AppBskyFeedGetRepostedBy.QueryParams,
opts?: AppBskyFeedGetRepostedBy.CallOptions,
Expand Down
67 changes: 67 additions & 0 deletions packages/api/src/client/lexicons.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5165,6 +5165,9 @@ export const schemaDict = {
likeCount: {
type: 'integer',
},
quoteCount: {
type: 'integer',
},
indexedAt: {
type: 'string',
format: 'datetime',
Expand Down Expand Up @@ -6280,6 +6283,69 @@ export const schemaDict = {
},
},
},
AppBskyFeedGetQuotes: {
lexicon: 1,
id: 'app.bsky.feed.getQuotes',
defs: {
main: {
type: 'query',
description: 'Get a list of quotes for a given post.',
parameters: {
type: 'params',
required: ['uri'],
properties: {
uri: {
type: 'string',
format: 'at-uri',
description: 'Reference (AT-URI) of post record',
},
cid: {
type: 'string',
format: 'cid',
description:
'If supplied, filters to quotes of specific version (by CID) of the post record.',
},
limit: {
type: 'integer',
minimum: 1,
maximum: 100,
default: 50,
},
cursor: {
type: 'string',
},
},
},
output: {
encoding: 'application/json',
schema: {
type: 'object',
required: ['uri', 'posts'],
properties: {
uri: {
type: 'string',
format: 'at-uri',
},
cid: {
type: 'string',
format: 'cid',
},
cursor: {
type: 'string',
},
posts: {
type: 'array',
items: {
type: 'ref',
ref: 'lex:app.bsky.feed.defs#postView',
},
},
},
},
},
},
},
},
AppBskyFeedGetRepostedBy: {
lexicon: 1,
id: 'app.bsky.feed.getRepostedBy',
Expand Down Expand Up @@ -11792,6 +11858,7 @@ export const ids = {
AppBskyFeedGetListFeed: 'app.bsky.feed.getListFeed',
AppBskyFeedGetPostThread: 'app.bsky.feed.getPostThread',
AppBskyFeedGetPosts: 'app.bsky.feed.getPosts',
AppBskyFeedGetQuotes: 'app.bsky.feed.getQuotes',
AppBskyFeedGetRepostedBy: 'app.bsky.feed.getRepostedBy',
AppBskyFeedGetSuggestedFeeds: 'app.bsky.feed.getSuggestedFeeds',
AppBskyFeedGetTimeline: 'app.bsky.feed.getTimeline',
Expand Down
1 change: 1 addition & 0 deletions packages/api/src/client/types/app/bsky/feed/defs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export interface PostView {
replyCount?: number
repostCount?: number
likeCount?: number
quoteCount?: number
indexedAt: string
viewer?: ViewerState
labels?: ComAtprotoLabelDefs.Label[]
Expand Down
44 changes: 44 additions & 0 deletions packages/api/src/client/types/app/bsky/feed/getQuotes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/**
* GENERATED CODE - DO NOT MODIFY
*/
import { Headers, XRPCError } from '@atproto/xrpc'
import { ValidationResult, BlobRef } from '@atproto/lexicon'
import { isObj, hasProp } from '../../../../util'
import { lexicons } from '../../../../lexicons'
import { CID } from 'multiformats/cid'
import * as AppBskyFeedDefs from './defs'

export interface QueryParams {
/** Reference (AT-URI) of post record */
uri: string
/** If supplied, filters to quotes of specific version (by CID) of the post record. */
cid?: string
limit?: number
cursor?: string
}

export type InputSchema = undefined

export interface OutputSchema {
uri: string
cid?: string
cursor?: string
posts: AppBskyFeedDefs.PostView[]
[k: string]: unknown
}

export interface CallOptions {
headers?: Headers
}

export interface Response {
success: boolean
headers: Headers
data: OutputSchema
}

export function toKnownErr(e: any) {
if (e instanceof XRPCError) {
}
return e
}
21 changes: 21 additions & 0 deletions packages/bsky/proto/bsky.proto
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,23 @@ message GetActorLikesResponse {
string cursor = 2;
}

//
// Quotes
//

message GetQuotesBySubjectRequest {
RecordRef subject = 1;
int32 limit = 2;
string cursor = 3;
}

message GetQuotesBySubjectResponse {
repeated RecordRef refs = 1;
string cursor = 2;
}

// - return post uris that quote the given subject uri

//
// Interactions
//
Expand All @@ -260,6 +277,7 @@ message GetInteractionCountsResponse {
repeated int32 likes = 1;
repeated int32 reposts = 2;
repeated int32 replies = 3;
repeated int32 quotes = 4;
}

message GetCountsForUsersRequest {
Expand Down Expand Up @@ -1087,6 +1105,9 @@ service Service {
rpc GetRepostsByActorAndSubjects(GetRepostsByActorAndSubjectsRequest) returns (GetRepostsByActorAndSubjectsResponse);
rpc GetActorReposts(GetActorRepostsRequest) returns (GetActorRepostsResponse);

// Quotes
rpc GetQuotesBySubject(GetQuotesBySubjectRequest) returns (GetQuotesBySubjectResponse);

// Interaction Counts
rpc GetInteractionCounts(GetInteractionCountsRequest) returns (GetInteractionCountsResponse);
rpc GetCountsForUsers(GetCountsForUsersRequest) returns (GetCountsForUsersResponse);
Expand Down
105 changes: 105 additions & 0 deletions packages/bsky/src/api/app/bsky/feed/getQuotes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import { Server } from '../../../../lexicon'
import AppContext from '../../../../context'
import { createPipeline } from '../../../../pipeline'
import { clearlyBadCursor, resHeaders } from '../../../util'
import {
HydrateCtx,
HydrationState,
Hydrator,
} from '../../../../hydration/hydrator'
import { Views } from '../../../../views'
import { mapDefined } from '@atproto/common'
import { QueryParams } from '../../../../lexicon/types/app/bsky/feed/getQuotes'
import { ItemRef, parseString } from '../../../../hydration/util'

export default function (server: Server, ctx: AppContext) {
const getQuotes = createPipeline(skeleton, hydration, noBlocks, presentation)
server.app.bsky.feed.getQuotes({
auth: ctx.authVerifier.standardOptional,
handler: async ({ params, auth, req }) => {
const { viewer, includeTakedowns } = ctx.authVerifier.parseCreds(auth)
const labelers = ctx.reqLabelers(req)
const hydrateCtx = await ctx.hydrator.createContext({
labelers,
viewer,
includeTakedowns,
})
const result = await getQuotes({ ...params, hydrateCtx }, ctx)
return {
encoding: 'application/json',
body: result,
headers: resHeaders({ labelers: hydrateCtx.labelers }),
}
},
})
}

const skeleton = async (inputs: {
ctx: Context
params: Params
}): Promise<Skeleton> => {
const { ctx, params } = inputs
if (clearlyBadCursor(params.cursor)) {
return { refs: [] }
}
const quotesRes = await ctx.hydrator.dataplane.getQuotesBySubject({
subject: { uri: params.uri, cid: params.cid },
cursor: params.cursor,
limit: params.limit,
})
return {
refs: quotesRes.refs,
cursor: parseString(quotesRes.cursor),
}
}

const hydration = async (inputs: {
ctx: Context
params: Params
skeleton: Skeleton
}) => {
const { ctx, params, skeleton } = inputs
return await ctx.hydrator.hydratePosts(skeleton.refs, params.hydrateCtx)
}

const noBlocks = (inputs: {
ctx: Context
skeleton: Skeleton
hydration: HydrationState
}) => {
const { ctx, skeleton, hydration } = inputs
skeleton.refs = skeleton.refs.filter((ref) => {
return !ctx.views.viewerBlockExists(ref.uri, hydration)
})
return skeleton
}

const presentation = (inputs: {
ctx: Context
params: Params
skeleton: Skeleton
hydration: HydrationState
}) => {
const { ctx, params, skeleton, hydration } = inputs
const postViews = mapDefined(skeleton.refs, (ref) => {
return ctx.views.post(ref.uri, hydration)
})
return {
posts: postViews,
cursor: skeleton.cursor,
uri: params.uri,
cid: params.cid,
}
}

type Context = {
hydrator: Hydrator
views: Views
}

type Params = QueryParams & { hydrateCtx: HydrateCtx }

type Skeleton = {
refs: ItemRef[]
cursor?: string
}
Loading

0 comments on commit 2a0c088

Please sign in to comment.