Trend schemas ()

trend schemas
This commit is contained in:
Daniel Holmgren 2022-11-09 14:44:46 -06:00 committed by GitHub
parent da8f055816
commit e6471a7419
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 325 additions and 3 deletions
lexicons/app/bsky
feed
notification
packages
api/src/client
index.tsschemas.ts
types/app/bsky/feed
pds/src

@ -0,0 +1,24 @@
{
"lexicon": 1,
"id": "app.bsky.feed.trend",
"type": "record",
"key": "tid",
"record": {
"type": "object",
"required": ["subject", "createdAt"],
"properties": {
"subject": {"$ref": "#/defs/subject"},
"createdAt": {"type": "string", "format": "date-time"}
}
},
"defs": {
"subject": {
"type": "object",
"required": ["uri", "cid"],
"properties": {
"uri": {"type": "string"},
"cid": {"type": "string"}
}
}
}
}

@ -44,7 +44,7 @@
},
"reason": {
"type": "string",
"$comment": "Expected values are 'vote', 'repost', 'follow', 'invite', 'mention' and 'reply'."
"$comment": "Expected values are 'vote', 'repost', 'trend', 'follow', 'invite', 'mention' and 'reply'."
},
"reasonSubject": {"type": "string"},
"record": {"type": "object"},

@ -44,6 +44,7 @@ import * as AppBskyFeedMediaEmbed from './types/app/bsky/feed/mediaEmbed'
import * as AppBskyFeedPost from './types/app/bsky/feed/post'
import * as AppBskyFeedRepost from './types/app/bsky/feed/repost'
import * as AppBskyFeedSetVote from './types/app/bsky/feed/setVote'
import * as AppBskyFeedTrend from './types/app/bsky/feed/trend'
import * as AppBskyFeedVote from './types/app/bsky/feed/vote'
import * as AppBskyGraphAssertion from './types/app/bsky/graph/assertion'
import * as AppBskyGraphConfirmation from './types/app/bsky/graph/confirmation'
@ -95,6 +96,7 @@ export * as AppBskyFeedMediaEmbed from './types/app/bsky/feed/mediaEmbed'
export * as AppBskyFeedPost from './types/app/bsky/feed/post'
export * as AppBskyFeedRepost from './types/app/bsky/feed/repost'
export * as AppBskyFeedSetVote from './types/app/bsky/feed/setVote'
export * as AppBskyFeedTrend from './types/app/bsky/feed/trend'
export * as AppBskyFeedVote from './types/app/bsky/feed/vote'
export * as AppBskyGraphAssertion from './types/app/bsky/graph/assertion'
export * as AppBskyGraphConfirmation from './types/app/bsky/graph/confirmation'
@ -640,6 +642,7 @@ export class FeedNS {
mediaEmbed: MediaEmbedRecord
post: PostRecord
repost: RepostRecord
trend: TrendRecord
vote: VoteRecord
constructor(service: ServiceClient) {
@ -647,6 +650,7 @@ export class FeedNS {
this.mediaEmbed = new MediaEmbedRecord(service)
this.post = new PostRecord(service)
this.repost = new RepostRecord(service)
this.trend = new TrendRecord(service)
this.vote = new VoteRecord(service)
}
@ -904,6 +908,67 @@ export class RepostRecord {
}
}
export class TrendRecord {
_service: ServiceClient
constructor(service: ServiceClient) {
this._service = service
}
async list(
params: Omit<ComAtprotoRepoListRecords.QueryParams, 'collection'>
): Promise<{
cursor?: string,
records: { uri: string, value: AppBskyFeedTrend.Record }[],
}> {
const res = await this._service.xrpc.call('com.atproto.repo.listRecords', {
collection: 'app.bsky.feed.trend',
...params,
})
return res.data
}
async get(
params: Omit<ComAtprotoRepoGetRecord.QueryParams, 'collection'>
): Promise<{ uri: string, cid: string, value: AppBskyFeedTrend.Record }> {
const res = await this._service.xrpc.call('com.atproto.repo.getRecord', {
collection: 'app.bsky.feed.trend',
...params,
})
return res.data
}
async create(
params: Omit<
ComAtprotoRepoCreateRecord.InputSchema,
'collection' | 'record'
>,
record: AppBskyFeedTrend.Record,
headers?: Record<string, string>
): Promise<{ uri: string, cid: string }> {
record.$type = 'app.bsky.feed.trend'
const res = await this._service.xrpc.call(
'com.atproto.repo.createRecord',
undefined,
{ collection: 'app.bsky.feed.trend', ...params, record },
{ encoding: 'application/json', headers }
)
return res.data
}
async delete(
params: Omit<ComAtprotoRepoDeleteRecord.QueryParams, 'collection'>,
headers?: Record<string, string>
): Promise<void> {
await this._service.xrpc.call(
'com.atproto.repo.deleteRecord',
undefined,
{ collection: 'app.bsky.feed.trend', ...params },
{ headers }
)
}
}
export class VoteRecord {
_service: ServiceClient

@ -2820,7 +2820,7 @@ export const methodSchemaDict: Record<string, MethodSchema> = {
reason: {
type: 'string',
$comment:
"Expected values are 'vote', 'repost', 'follow', 'invite', 'mention' and 'reply'.",
"Expected values are 'vote', 'repost', 'trend', 'follow', 'invite', 'mention' and 'reply'.",
},
reasonSubject: {
type: 'string',
@ -2879,7 +2879,7 @@ export const methodSchemaDict: Record<string, MethodSchema> = {
reason: {
type: 'string',
$comment:
"Expected values are 'vote', 'repost', 'follow', 'invite', 'mention' and 'reply'.",
"Expected values are 'vote', 'repost', 'trend', 'follow', 'invite', 'mention' and 'reply'.",
},
reasonSubject: {
type: 'string',
@ -2931,6 +2931,7 @@ export const ids = {
AppBskyFeedMediaEmbed: 'app.bsky.feed.mediaEmbed',
AppBskyFeedPost: 'app.bsky.feed.post',
AppBskyFeedRepost: 'app.bsky.feed.repost',
AppBskyFeedTrend: 'app.bsky.feed.trend',
AppBskyFeedVote: 'app.bsky.feed.vote',
AppBskyGraphAssertion: 'app.bsky.graph.assertion',
AppBskyGraphConfirmation: 'app.bsky.graph.confirmation',
@ -3209,6 +3210,53 @@ export const recordSchemaDict: Record<string, RecordSchema> = {
},
},
},
'app.bsky.feed.trend': {
lexicon: 1,
id: 'app.bsky.feed.trend',
type: 'record',
key: 'tid',
record: {
type: 'object',
required: ['subject', 'createdAt'],
properties: {
subject: {
$ref: '#/$defs/subject',
},
createdAt: {
type: 'string',
format: 'date-time',
},
},
$defs: {
subject: {
type: 'object',
required: ['uri', 'cid'],
properties: {
uri: {
type: 'string',
},
cid: {
type: 'string',
},
},
},
},
},
defs: {
subject: {
type: 'object',
required: ['uri', 'cid'],
properties: {
uri: {
type: 'string',
},
cid: {
type: 'string',
},
},
},
},
},
'app.bsky.feed.vote': {
lexicon: 1,
id: 'app.bsky.feed.vote',

@ -0,0 +1,13 @@
/**
* GENERATED CODE - DO NOT MODIFY
*/
export interface Record {
subject: Subject;
createdAt: string;
[k: string]: unknown;
}
export interface Subject {
uri: string;
cid: string;
[k: string]: unknown;
}

@ -13,6 +13,7 @@ import * as profile from './records/profile'
import * as post from './records/post'
import * as vote from './records/vote'
import * as repost from './records/repost'
import * as trend from './records/trend'
import * as follow from './records/follow'
export type DatabaseSchema = user.PartialDB &
@ -29,5 +30,6 @@ export type DatabaseSchema = user.PartialDB &
post.PartialDB &
vote.PartialDB &
repost.PartialDB &
trend.PartialDB &
follow.PartialDB &
assertion.PartialDB

@ -8,6 +8,7 @@ import * as Declaration from './records/declaration'
import * as Post from './records/post'
import * as Vote from './records/vote'
import * as Repost from './records/repost'
import * as Trend from './records/trend'
import * as Follow from './records/follow'
import * as Assertion from './records/assertion'
import * as Confirmation from './records/confirmation'
@ -33,6 +34,7 @@ export class Database {
post: Post.PluginType
vote: Vote.PluginType
repost: Repost.PluginType
trend: Trend.PluginType
follow: Follow.PluginType
profile: Profile.PluginType
assertion: Assertion.PluginType
@ -50,6 +52,7 @@ export class Database {
post: Post.makePlugin(db),
vote: Vote.makePlugin(db),
repost: Repost.makePlugin(db),
trend: Trend.makePlugin(db),
follow: Follow.makePlugin(db),
assertion: Assertion.makePlugin(db),
confirmation: Confirmation.makePlugin(db),

@ -19,6 +19,7 @@ const followTable = 'follow'
const postTable = 'post'
const postEntityTable = 'post_entity'
const repostTable = 'repost'
const trendTable = 'trend'
const voteTable = 'vote'
export async function up(db: Kysely<unknown>, dialect: Dialect): Promise<void> {
@ -227,6 +228,16 @@ export async function up(db: Kysely<unknown>, dialect: Dialect): Promise<void> {
.addColumn('createdAt', 'varchar', (col) => col.notNull())
.addColumn('indexedAt', 'varchar', (col) => col.notNull())
.execute()
await db.schema
.createTable(trendTable)
.addColumn('uri', 'varchar', (col) => col.primaryKey())
.addColumn('cid', 'varchar', (col) => col.notNull())
.addColumn('creator', 'varchar', (col) => col.notNull())
.addColumn('subject', 'varchar', (col) => col.notNull())
.addColumn('subjectCid', 'varchar', (col) => col.notNull())
.addColumn('createdAt', 'varchar', (col) => col.notNull())
.addColumn('indexedAt', 'varchar', (col) => col.notNull())
.execute()
await db.schema
.createTable(voteTable)
.addColumn('uri', 'varchar', (col) => col.primaryKey())
@ -242,6 +253,7 @@ export async function up(db: Kysely<unknown>, dialect: Dialect): Promise<void> {
export async function down(db: Kysely<unknown>): Promise<void> {
await db.schema.dropTable(voteTable).execute()
await db.schema.dropTable(trendTable).execute()
await db.schema.dropTable(repostTable).execute()
await db.schema.dropTable(postEntityTable).execute()
await db.schema.dropTable(postTable).execute()

@ -0,0 +1,93 @@
import { Kysely } from 'kysely'
import { AtUri } from '@atproto/uri'
import * as Trend from '../../lexicon/types/app/bsky/feed/trend'
import { DbRecordPlugin, Notification } from '../types'
import * as schemas from '../schemas'
import { CID } from 'multiformats/cid'
const type = schemas.ids.AppBskyFeedTrend
const tableName = 'trend'
export interface BskyTrend {
uri: string
cid: string
creator: string
subject: string
subjectCid: string
createdAt: string
indexedAt: string
}
export type PartialDB = { [tableName]: BskyTrend }
const validator = schemas.records.createRecordValidator(type)
const matchesSchema = (obj: unknown): obj is Trend.Record => {
return validator.isValid(obj)
}
const validateSchema = (obj: unknown) => validator.validate(obj)
const insertFn =
(db: Kysely<PartialDB>) =>
async (
uri: AtUri,
cid: CID,
obj: unknown,
timestamp?: string,
): Promise<void> => {
if (!matchesSchema(obj)) {
throw new Error(`Record does not match schema: ${type}`)
}
await db
.insertInto(tableName)
.values({
uri: uri.toString(),
cid: cid.toString(),
creator: uri.host,
subject: obj.subject.uri,
subjectCid: obj.subject.cid,
createdAt: obj.createdAt,
indexedAt: timestamp || new Date().toISOString(),
})
.execute()
}
const deleteFn =
(db: Kysely<PartialDB>) =>
async (uri: AtUri): Promise<void> => {
await db.deleteFrom(tableName).where('uri', '=', uri.toString()).execute()
}
const notifsForRecord = (
uri: AtUri,
cid: CID,
obj: unknown,
): Notification[] => {
if (!matchesSchema(obj)) {
throw new Error(`Record does not match schema: ${type}`)
}
const subjectUri = new AtUri(obj.subject.uri)
const notif = {
userDid: subjectUri.host,
author: uri.host,
recordUri: uri.toString(),
recordCid: cid.toString(),
reason: 'trend',
reasonSubject: subjectUri.toString(),
}
return [notif]
}
export type PluginType = DbRecordPlugin<Trend.Record>
export const makePlugin = (db: Kysely<PartialDB>): PluginType => {
return {
collection: type,
validateSchema,
matchesSchema,
insert: insertFn(db),
delete: deleteFn(db),
notifsForRecord,
}
}
export default makePlugin

@ -33,6 +33,7 @@ export type Notification = {
export type NotificationReason =
| 'vote'
| 'repost'
| 'trend'
| 'follow'
| 'invite'
| 'reply'

@ -2931,6 +2931,7 @@ export const ids = {
AppBskyFeedMediaEmbed: 'app.bsky.feed.mediaEmbed',
AppBskyFeedPost: 'app.bsky.feed.post',
AppBskyFeedRepost: 'app.bsky.feed.repost',
AppBskyFeedTrend: 'app.bsky.feed.trend',
AppBskyFeedVote: 'app.bsky.feed.vote',
AppBskyGraphAssertion: 'app.bsky.graph.assertion',
AppBskyGraphConfirmation: 'app.bsky.graph.confirmation',
@ -3209,6 +3210,53 @@ export const recordSchemaDict: Record<string, RecordSchema> = {
},
},
},
'app.bsky.feed.trend': {
lexicon: 1,
id: 'app.bsky.feed.trend',
type: 'record',
key: 'tid',
record: {
type: 'object',
required: ['subject', 'createdAt'],
properties: {
subject: {
$ref: '#/$defs/subject',
},
createdAt: {
type: 'string',
format: 'date-time',
},
},
$defs: {
subject: {
type: 'object',
required: ['uri', 'cid'],
properties: {
uri: {
type: 'string',
},
cid: {
type: 'string',
},
},
},
},
},
defs: {
subject: {
type: 'object',
required: ['uri', 'cid'],
properties: {
uri: {
type: 'string',
},
cid: {
type: 'string',
},
},
},
},
},
'app.bsky.feed.vote': {
lexicon: 1,
id: 'app.bsky.feed.vote',

@ -0,0 +1,13 @@
/**
* GENERATED CODE - DO NOT MODIFY
*/
export interface Record {
subject: Subject;
createdAt: string;
[k: string]: unknown;
}
export interface Subject {
uri: string;
cid: string;
[k: string]: unknown;
}