Skip to main content
Glama
queries.ts23 kB
import Database from "better-sqlite3"; import { initSchema } from "./schema.js"; // Types export interface TokenProperty { property: string; value: string; valueNumber?: number; valueUnit?: string; } export interface Token { category: string; subcategory?: string; name: string; path: string; cssVariable?: string; scssVariable?: string; valueRaw: string; valueNumber?: number; valueUnit?: string; valueComputed?: string; description?: string; platform?: string; sourceFile?: string; properties?: TokenProperty[]; } export interface ComponentProp { name: string; type?: string; defaultValue?: string; required?: boolean; options?: string[]; description?: string; } export interface ComponentSlot { name: string; description?: string; } export interface ComponentEvent { name: string; payload?: string; description?: string; } export interface ComponentExample { framework: string; title?: string; code: string; description?: string; } export interface Component { name: string; slug: string; category?: string; description?: string; frameworks?: string[]; props?: ComponentProp[]; slots?: ComponentSlot[]; events?: ComponentEvent[]; examples?: ComponentExample[]; cssClasses?: string[]; } export interface Documentation { title: string; path: string; content: string; category?: string; keywords?: string[]; } export interface CssUtilityExample { title?: string; code: string; } export interface CssUtility { name: string; slug: string; category: string; description?: string; classes: string[]; examples: CssUtilityExample[]; } export interface Icon { name: string; iconName: string; type: string; size: number; viewBox: string; paths: string; } // Database initialization export function initDatabase(dbPath: string): Database.Database { const db = new Database(dbPath); db.pragma("journal_mode = WAL"); initSchema(db); return db; } // Token operations export function insertTokens(db: Database.Database, tokens: Token[]): void { const tokenStmt = db.prepare(` INSERT INTO tokens ( category, subcategory, name, path, css_variable, scss_variable, value_raw, value_number, value_unit, value_computed, description, platform, source_file ) VALUES ( @category, @subcategory, @name, @path, @cssVariable, @scssVariable, @valueRaw, @valueNumber, @valueUnit, @valueComputed, @description, @platform, @sourceFile ) `); const propertyStmt = db.prepare(` INSERT INTO token_properties (token_id, property, value, value_number, value_unit) VALUES (@tokenId, @property, @value, @valueNumber, @valueUnit) `); const insertMany = db.transaction((items: Token[]) => { for (const item of items) { const result = tokenStmt.run({ category: item.category, subcategory: item.subcategory ?? null, name: item.name, path: item.path, cssVariable: item.cssVariable ?? null, scssVariable: item.scssVariable ?? null, valueRaw: item.valueRaw, valueNumber: item.valueNumber ?? null, valueUnit: item.valueUnit ?? null, valueComputed: item.valueComputed ?? null, description: item.description ?? null, platform: item.platform ?? "all", sourceFile: item.sourceFile ?? null, }); // Insert token properties if any (for composite tokens like shadows) if (item.properties && item.properties.length > 0) { const tokenId = result.lastInsertRowid as number; for (const prop of item.properties) { propertyStmt.run({ tokenId, property: prop.property, value: prop.value, valueNumber: prop.valueNumber ?? null, valueUnit: prop.valueUnit ?? null, }); } } } }); insertMany(tokens); } interface TokenRow { id: number; category: string; subcategory: string | null; name: string; path: string; css_variable: string | null; scss_variable: string | null; value_raw: string; value_number: number | null; value_unit: string | null; value_computed: string | null; description: string | null; platform: string; source_file: string | null; } interface TokenPropertyRow { property: string; value: string; value_number: number | null; value_unit: string | null; } function rowToToken(row: TokenRow, properties?: TokenPropertyRow[]): Token { const token: Token = { category: row.category, subcategory: row.subcategory ?? undefined, name: row.name, path: row.path, cssVariable: row.css_variable ?? undefined, scssVariable: row.scss_variable ?? undefined, valueRaw: row.value_raw, valueNumber: row.value_number ?? undefined, valueUnit: row.value_unit ?? undefined, valueComputed: row.value_computed ?? undefined, description: row.description ?? undefined, platform: row.platform, sourceFile: row.source_file ?? undefined, }; if (properties && properties.length > 0) { token.properties = properties.map((p) => ({ property: p.property, value: p.value, valueNumber: p.value_number ?? undefined, valueUnit: p.value_unit ?? undefined, })); } return token; } export function getTokensByCategory(db: Database.Database, category: string): Token[] { const rows = category === "all" ? (db.prepare("SELECT * FROM tokens").all() as TokenRow[]) : (db.prepare("SELECT * FROM tokens WHERE category = ?").all(category) as TokenRow[]); return rows.map((row) => { const properties = db .prepare( "SELECT property, value, value_number, value_unit FROM token_properties WHERE token_id = ?" ) .all(row.id) as TokenPropertyRow[]; return rowToToken(row, properties); }); } export function getTokensBySubcategory( db: Database.Database, category: string, subcategory: string ): Token[] { const rows = db .prepare("SELECT * FROM tokens WHERE category = ? AND subcategory = ?") .all(category, subcategory) as TokenRow[]; return rows.map((row) => { const properties = db .prepare( "SELECT property, value, value_number, value_unit FROM token_properties WHERE token_id = ?" ) .all(row.id) as TokenPropertyRow[]; return rowToToken(row, properties); }); } export function getTokenByPath(db: Database.Database, path: string): Token | undefined { const row = db.prepare("SELECT * FROM tokens WHERE path = ?").get(path) as TokenRow | undefined; if (!row) return undefined; const properties = db .prepare( "SELECT property, value, value_number, value_unit FROM token_properties WHERE token_id = ?" ) .all(row.id) as TokenPropertyRow[]; return rowToToken(row, properties); } export function searchTokens(db: Database.Database, query: string, limit: number = 20): Token[] { const rows = db .prepare( ` SELECT t.* FROM tokens_fts JOIN tokens t ON tokens_fts.rowid = t.id WHERE tokens_fts MATCH ? ORDER BY rank LIMIT ? ` ) .all(query, limit) as TokenRow[]; return rows.map((row) => { const properties = db .prepare( "SELECT property, value, value_number, value_unit FROM token_properties WHERE token_id = ?" ) .all(row.id) as TokenPropertyRow[]; return rowToToken(row, properties); }); } // Component operations export function insertComponent(db: Database.Database, component: Component): number { const result = db .prepare( ` INSERT INTO components (name, slug, category, description, frameworks) VALUES (@name, @slug, @category, @description, @frameworks) ` ) .run({ name: component.name, slug: component.slug, category: component.category ?? null, description: component.description ?? null, frameworks: component.frameworks ? JSON.stringify(component.frameworks) : null, }); const componentId = result.lastInsertRowid as number; // Insert props if (component.props && component.props.length > 0) { const propStmt = db.prepare(` INSERT INTO component_props (component_id, name, type, default_value, required, options, description) VALUES (@componentId, @name, @type, @defaultValue, @required, @options, @description) `); for (const prop of component.props) { propStmt.run({ componentId, name: prop.name, type: prop.type ?? null, defaultValue: prop.defaultValue ?? null, required: prop.required ? 1 : 0, options: prop.options ? JSON.stringify(prop.options) : null, description: prop.description ?? null, }); } } // Insert slots if (component.slots && component.slots.length > 0) { const slotStmt = db.prepare(` INSERT INTO component_slots (component_id, name, description) VALUES (@componentId, @name, @description) `); for (const slot of component.slots) { slotStmt.run({ componentId, name: slot.name, description: slot.description ?? null, }); } } // Insert events if (component.events && component.events.length > 0) { const eventStmt = db.prepare(` INSERT INTO component_events (component_id, name, payload, description) VALUES (@componentId, @name, @payload, @description) `); for (const event of component.events) { eventStmt.run({ componentId, name: event.name, payload: event.payload ?? null, description: event.description ?? null, }); } } // Insert examples if (component.examples && component.examples.length > 0) { const exampleStmt = db.prepare(` INSERT INTO component_examples (component_id, framework, title, code, description) VALUES (@componentId, @framework, @title, @code, @description) `); for (const example of component.examples) { exampleStmt.run({ componentId, framework: example.framework, title: example.title ?? null, code: example.code, description: example.description ?? null, }); } } // Insert CSS classes if (component.cssClasses && component.cssClasses.length > 0) { const cssStmt = db.prepare(` INSERT INTO component_css_classes (component_id, class_name) VALUES (@componentId, @className) `); for (const className of component.cssClasses) { cssStmt.run({ componentId, className }); } } return componentId; } export function insertComponents(db: Database.Database, components: Component[]): void { const transaction = db.transaction((items: Component[]) => { for (const component of items) { insertComponent(db, component); } }); transaction(components); } export function getComponentBySlug(db: Database.Database, slug: string): Component | null { const row = db.prepare("SELECT * FROM components WHERE slug = ? COLLATE NOCASE").get(slug) as | { id: number; name: string; slug: string; category: string; description: string; frameworks: string; } | undefined; if (!row) return null; const props = db .prepare("SELECT * FROM component_props WHERE component_id = ?") .all(row.id) as Array<{ name: string; type: string; default_value: string; required: number; options: string; description: string; }>; const slots = db .prepare("SELECT * FROM component_slots WHERE component_id = ?") .all(row.id) as Array<{ name: string; description: string }>; const events = db .prepare("SELECT * FROM component_events WHERE component_id = ?") .all(row.id) as Array<{ name: string; payload: string; description: string }>; const examples = db .prepare("SELECT * FROM component_examples WHERE component_id = ?") .all(row.id) as Array<{ framework: string; title: string; code: string; description: string; }>; const cssClasses = db .prepare("SELECT class_name FROM component_css_classes WHERE component_id = ?") .all(row.id) as Array<{ class_name: string }>; return { name: row.name, slug: row.slug, category: row.category, description: row.description, frameworks: row.frameworks ? JSON.parse(row.frameworks) : [], props: props.map((p) => ({ name: p.name, type: p.type, defaultValue: p.default_value, required: p.required === 1, options: p.options ? JSON.parse(p.options) : undefined, description: p.description, })), slots: slots.map((s) => ({ name: s.name, description: s.description, })), events: events.map((e) => ({ name: e.name, payload: e.payload, description: e.description, })), examples: examples.map((ex) => ({ framework: ex.framework, title: ex.title, code: ex.code, description: ex.description, })), cssClasses: cssClasses.map((c) => c.class_name), }; } export function listComponents( db: Database.Database, category?: string ): Array<{ name: string; slug: string; category: string; description: string }> { if (category && category !== "all") { return db .prepare("SELECT name, slug, category, description FROM components WHERE category = ?") .all(category) as Array<{ name: string; slug: string; category: string; description: string; }>; } return db.prepare("SELECT name, slug, category, description FROM components").all() as Array<{ name: string; slug: string; category: string; description: string; }>; } // Documentation operations export function insertDocs(db: Database.Database, docs: Documentation[]): void { const stmt = db.prepare(` INSERT INTO documentation (title, path, content, category, keywords) VALUES (@title, @path, @content, @category, @keywords) `); const insertMany = db.transaction((items: Documentation[]) => { for (const item of items) { stmt.run({ title: item.title, path: item.path, content: item.content, category: item.category ?? null, keywords: item.keywords ? JSON.stringify(item.keywords) : null, }); } }); insertMany(docs); } export function searchDocumentation( db: Database.Database, query: string, limit: number = 5 ): Array<{ title: string; path: string; snippet: string; category: string }> { const results = db .prepare( ` SELECT d.title, d.path, d.category, snippet(docs_fts, 1, '<mark>', '</mark>', '...', 64) as snippet FROM docs_fts JOIN documentation d ON docs_fts.rowid = d.id WHERE docs_fts MATCH ? ORDER BY rank LIMIT ? ` ) .all(query, limit) as Array<{ title: string; path: string; snippet: string; category: string }>; return results; } export function getDocumentationByPath( db: Database.Database, path: string ): Documentation | undefined { return db.prepare("SELECT * FROM documentation WHERE path = ?").get(path) as | Documentation | undefined; } // CSS Utility operations export function insertCssUtility(db: Database.Database, utility: CssUtility): number { const result = db .prepare( ` INSERT INTO css_utilities (name, slug, category, description) VALUES (@name, @slug, @category, @description) ` ) .run({ name: utility.name, slug: utility.slug, category: utility.category, description: utility.description ?? null, }); const utilityId = result.lastInsertRowid as number; // Insert CSS classes if (utility.classes && utility.classes.length > 0) { const classStmt = db.prepare(` INSERT INTO css_utility_classes (utility_id, class_name) VALUES (@utilityId, @className) `); for (const className of utility.classes) { classStmt.run({ utilityId, className }); } } // Insert examples if (utility.examples && utility.examples.length > 0) { const exampleStmt = db.prepare(` INSERT INTO css_utility_examples (utility_id, title, code) VALUES (@utilityId, @title, @code) `); for (const example of utility.examples) { exampleStmt.run({ utilityId, title: example.title ?? null, code: example.code, }); } } return utilityId; } export function insertCssUtilities(db: Database.Database, utilities: CssUtility[]): void { const transaction = db.transaction((items: CssUtility[]) => { for (const utility of items) { insertCssUtility(db, utility); } }); transaction(utilities); } export function getCssUtility(db: Database.Database, name: string): CssUtility | null { const row = db .prepare("SELECT * FROM css_utilities WHERE name = ? COLLATE NOCASE OR slug = ? COLLATE NOCASE") .get(name, name) as | { id: number; name: string; slug: string; category: string; description: string } | undefined; if (!row) return null; const classes = db .prepare("SELECT class_name FROM css_utility_classes WHERE utility_id = ?") .all(row.id) as Array<{ class_name: string }>; const examples = db .prepare("SELECT title, code FROM css_utility_examples WHERE utility_id = ?") .all(row.id) as Array<{ title: string; code: string }>; return { name: row.name, slug: row.slug, category: row.category, description: row.description, classes: classes.map((c) => c.class_name), examples: examples.map((e) => ({ title: e.title, code: e.code, })), }; } export function listCssUtilities( db: Database.Database, category?: string ): Array<{ name: string; slug: string; category: string; description: string; classCount: number; }> { const query = category && category !== "all" ? `SELECT u.name, u.slug, u.category, u.description, (SELECT COUNT(*) FROM css_utility_classes WHERE utility_id = u.id) as classCount FROM css_utilities u WHERE u.category = ?` : `SELECT u.name, u.slug, u.category, u.description, (SELECT COUNT(*) FROM css_utility_classes WHERE utility_id = u.id) as classCount FROM css_utilities u`; if (category && category !== "all") { return db.prepare(query).all(category) as Array<{ name: string; slug: string; category: string; description: string; classCount: number; }>; } return db.prepare(query).all() as Array<{ name: string; slug: string; category: string; description: string; classCount: number; }>; } // Icon operations export function insertIcons(db: Database.Database, icons: Icon[]): void { const stmt = db.prepare(` INSERT INTO icons (name, icon_name, type, size, view_box, paths) VALUES (@name, @iconName, @type, @size, @viewBox, @paths) `); const insertMany = db.transaction((items: Icon[]) => { for (const item of items) { stmt.run({ name: item.name, iconName: item.iconName, type: item.type, size: item.size, viewBox: item.viewBox, paths: item.paths, }); } }); insertMany(icons); } interface IconRow { id: number; name: string; icon_name: string; type: string; size: number; view_box: string; paths: string; } function rowToIcon(row: IconRow): Icon { return { name: row.name, iconName: row.icon_name, type: row.type, size: row.size, viewBox: row.view_box, paths: row.paths, }; } export function searchIcons( db: Database.Database, query: string, options?: { type?: string; size?: number; limit?: number } ): Icon[] { const limit = options?.limit ?? 20; let sql = ` SELECT i.* FROM icons_fts JOIN icons i ON icons_fts.rowid = i.id WHERE icons_fts MATCH ? `; const params: (string | number)[] = [query]; if (options?.type) { sql += " AND i.type = ?"; params.push(options.type); } if (options?.size) { sql += " AND i.size = ?"; params.push(options.size); } sql += " ORDER BY rank LIMIT ?"; params.push(limit); const rows = db.prepare(sql).all(...params) as IconRow[]; return rows.map(rowToIcon); } export function getIconByName(db: Database.Database, name: string): Icon | null { const row = db.prepare("SELECT * FROM icons WHERE name = ? COLLATE NOCASE").get(name) as | IconRow | undefined; if (!row) return null; return rowToIcon(row); } export function getIconsByType(db: Database.Database, type: string, limit: number = 50): Icon[] { const rows = db .prepare("SELECT * FROM icons WHERE type = ? ORDER BY icon_name, size LIMIT ?") .all(type, limit) as IconRow[]; return rows.map(rowToIcon); } export function listIconTypes(db: Database.Database): Array<{ type: string; count: number }> { return db .prepare("SELECT type, COUNT(*) as count FROM icons GROUP BY type ORDER BY count DESC") .all() as Array<{ type: string; count: number }>; } export function listIcons( db: Database.Database, options?: { type?: string; size?: number; limit?: number } ): Icon[] { const limit = options?.limit ?? 100; let sql = "SELECT * FROM icons WHERE 1=1"; const params: (string | number)[] = []; if (options?.type) { sql += " AND type = ?"; params.push(options.type); } if (options?.size) { sql += " AND size = ?"; params.push(options.size); } sql += " ORDER BY icon_name, size LIMIT ?"; params.push(limit); const rows = db.prepare(sql).all(...params) as IconRow[]; return rows.map(rowToIcon); } // Utility functions export function clearDatabase(db: Database.Database): void { db.exec(` DELETE FROM token_properties; DELETE FROM tokens; DELETE FROM component_css_classes; DELETE FROM component_examples; DELETE FROM component_events; DELETE FROM component_slots; DELETE FROM component_props; DELETE FROM components; DELETE FROM css_utility_classes; DELETE FROM css_utility_examples; DELETE FROM css_utilities; DELETE FROM documentation; DELETE FROM icons; `); } export function getDatabaseStats(db: Database.Database): { tokens: number; components: number; cssUtilities: number; documentation: number; icons: number; } { const tokens = db.prepare("SELECT COUNT(*) as count FROM tokens").get() as { count: number }; const components = db.prepare("SELECT COUNT(*) as count FROM components").get() as { count: number; }; const cssUtilities = db.prepare("SELECT COUNT(*) as count FROM css_utilities").get() as { count: number; }; const documentation = db.prepare("SELECT COUNT(*) as count FROM documentation").get() as { count: number; }; const icons = db.prepare("SELECT COUNT(*) as count FROM icons").get() as { count: number }; return { tokens: tokens.count, components: components.count, cssUtilities: cssUtilities.count, documentation: documentation.count, icons: icons.count, }; }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/MerzoukeMansouri/adeo-mozaic-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server