Barazo AppView backend barazo.forum
at main 79 lines 3.2 kB view raw
1import { 2 pgTable, 3 pgPolicy, 4 text, 5 integer, 6 timestamp, 7 jsonb, 8 boolean, 9 index, 10} from 'drizzle-orm/pg-core' 11import { sql } from 'drizzle-orm' 12import { appRole } from './roles.js' 13 14export const topics = pgTable( 15 'topics', 16 { 17 uri: text('uri').primaryKey(), 18 rkey: text('rkey').notNull(), 19 authorDid: text('author_did').notNull(), 20 title: text('title').notNull(), 21 content: text('content').notNull(), 22 category: text('category').notNull(), 23 site: text('site'), 24 tags: jsonb('tags').$type<string[]>(), 25 communityDid: text('community_did').notNull(), 26 cid: text('cid').notNull(), 27 labels: jsonb('labels').$type<{ values: { val: string }[] }>(), 28 replyCount: integer('reply_count').notNull().default(0), 29 reactionCount: integer('reaction_count').notNull().default(0), 30 voteCount: integer('vote_count').notNull().default(0), 31 lastActivityAt: timestamp('last_activity_at', { withTimezone: true }).notNull().defaultNow(), 32 publishedAt: timestamp('published_at', { withTimezone: true }).notNull(), 33 indexedAt: timestamp('indexed_at', { withTimezone: true }).notNull().defaultNow(), 34 isLocked: boolean('is_locked').notNull().default(false), 35 isPinned: boolean('is_pinned').notNull().default(false), 36 pinnedAt: timestamp('pinned_at', { withTimezone: true }), 37 pinnedScope: text('pinned_scope', { enum: ['category', 'forum'] }), 38 isModDeleted: boolean('is_mod_deleted').notNull().default(false), 39 isAuthorDeleted: boolean('is_author_deleted').notNull().default(false), 40 moderationStatus: text('moderation_status', { 41 enum: ['approved', 'held', 'rejected'], 42 }) 43 .notNull() 44 .default('approved'), 45 /** Trust status based on account age at indexing time. 'new' for accounts < 24h old. */ 46 trustStatus: text('trust_status', { 47 enum: ['trusted', 'new'], 48 }) 49 .notNull() 50 .default('trusted'), 51 // Note: search_vector (tsvector) and embedding (vector) columns exist in the 52 // database but are managed outside Drizzle schema (see migration 0010). 53 // search_vector is maintained by a database trigger. 54 // embedding is nullable vector(768) for optional semantic search. 55 }, 56 (table) => [ 57 index('topics_author_did_idx').on(table.authorDid), 58 index('topics_category_idx').on(table.category), 59 index('topics_published_at_idx').on(table.publishedAt), 60 index('topics_last_activity_at_idx').on(table.lastActivityAt), 61 index('topics_community_did_idx').on(table.communityDid), 62 index('topics_moderation_status_idx').on(table.moderationStatus), 63 index('topics_trust_status_idx').on(table.trustStatus), 64 index('topics_community_category_activity_idx').on( 65 table.communityDid, 66 table.category, 67 table.lastActivityAt 68 ), 69 index('topics_pinned_scope_idx').on(table.pinnedScope), 70 index('topics_author_did_rkey_idx').on(table.authorDid, table.rkey), 71 pgPolicy('tenant_isolation', { 72 as: 'permissive', 73 to: appRole, 74 for: 'all', 75 using: sql`community_did = current_setting('app.current_community_did', true)`, 76 withCheck: sql`community_did = current_setting('app.current_community_did', true)`, 77 }), 78 ] 79).enableRLS()