UNPKG

aisdk5-news-package

Version:

A comprehensive RSS news aggregation package for chat applications

92 lines (85 loc) 3.7 kB
import { pgTable, uuid, varchar, text, timestamp, json, boolean, integer, index, primaryKey, foreignKey } from 'drizzle-orm/pg-core'; import { InferSelectModel } from 'drizzle-orm'; // RSS Feed table export const newsRssFeed = pgTable('news_rss_feeds', { id: uuid('id').primaryKey().notNull().defaultRandom(), name: varchar('name', { length: 255 }).notNull(), url: text('url').notNull().unique(), category: varchar('category', { length: 100 }).notNull(), isActive: boolean('is_active').notNull().default(true), lastFetchedAt: timestamp('last_fetched_at'), fetchInterval: integer('fetch_interval').notNull().default(30), // minutes errorCount: integer('error_count').notNull().default(0), createdAt: timestamp('created_at').notNull().defaultNow(), updatedAt: timestamp('updated_at').notNull().defaultNow(), }, (table) => ({ isActiveIdx: index('idx_feeds_is_active').on(table.isActive), lastFetchedIdx: index('idx_feeds_last_fetched').on(table.lastFetchedAt), })); export type NewsRssFeed = InferSelectModel<typeof newsRssFeed>; // Article table export const newsArticle = pgTable('news_articles', { id: uuid('id').primaryKey().notNull().defaultRandom(), title: text('title').notNull(), description: text('description'), content: text('content'), url: text('url').notNull().unique(), imageUrl: text('image_url'), publishedAt: timestamp('published_at').notNull(), fetchedAt: timestamp('fetched_at').notNull().defaultNow(), feedId: uuid('feed_id') .notNull() .references(() => newsRssFeed.id, { onDelete: 'cascade' }), category: varchar('category', { length: 100 }).notNull(), tags: json('tags').$type<string[]>().notNull().default([]), isActive: boolean('is_active').notNull().default(true), // Media extraction fields mediaElements: json('media_elements').$type<any[]>().notNull().default([]), hasAudio: boolean('has_audio').notNull().default(false), hasVideo: boolean('has_video').notNull().default(false), mediaExtractedAt: timestamp('media_extracted_at'), mediaExtractionError: text('media_extraction_error'), createdAt: timestamp('created_at').notNull().defaultNow(), updatedAt: timestamp('updated_at').notNull().defaultNow(), }, (table) => ({ publishedAtIdx: index('idx_articles_published_at').on(table.publishedAt), categoryIdx: index('idx_articles_category').on(table.category), feedIdIdx: index('idx_articles_feed_id').on(table.feedId), isActiveIdx: index('idx_articles_is_active').on(table.isActive), categoryActiveIdx: index('idx_articles_category_active').on(table.category, table.isActive), hasAudioIdx: index('idx_articles_has_audio').on(table.hasAudio), hasVideoIdx: index('idx_articles_has_video').on(table.hasVideo), mediaExtractedAtIdx: index('idx_articles_media_extracted_at').on(table.mediaExtractedAt), })); export type NewsArticle = InferSelectModel<typeof newsArticle>; // Saved articles table (generic - can be customized for different user table setups) export const newsSavedArticle = pgTable('news_saved_articles', { userId: uuid('user_id').notNull(), articleId: uuid('article_id') .notNull() .references(() => newsArticle.id, { onDelete: 'cascade' }), savedAt: timestamp('saved_at').notNull().defaultNow(), }, (table) => ({ pk: primaryKey({ columns: [table.userId, table.articleId] }), userIdx: index('idx_saved_articles_user').on(table.userId), savedAtIdx: index('idx_saved_articles_saved_at').on(table.savedAt), })); export type NewsSavedArticle = InferSelectModel<typeof newsSavedArticle>; // Type exports for easy importing export type { NewsRssFeed as RSSFeed, NewsArticle as Article, NewsSavedArticle as SavedArticle };