141 lines
4.5 KiB
JavaScript
141 lines
4.5 KiB
JavaScript
/**
|
|
* Posts Module - Database
|
|
* Creates zen_posts and zen_posts_category tables.
|
|
*/
|
|
|
|
import { query } from '@hykocx/zen/database';
|
|
import { getPostsConfig } from './config.js';
|
|
|
|
async function tableExists(tableName) {
|
|
const result = await query(
|
|
`SELECT EXISTS (
|
|
SELECT FROM information_schema.tables
|
|
WHERE table_schema = 'public'
|
|
AND table_name = $1
|
|
)`,
|
|
[tableName]
|
|
);
|
|
return result.rows[0].exists;
|
|
}
|
|
|
|
async function createPostsCategoryTable() {
|
|
const tableName = 'zen_posts_category';
|
|
const exists = await tableExists(tableName);
|
|
|
|
if (exists) {
|
|
console.log(`- Table already exists: ${tableName}`);
|
|
return { created: false, tableName };
|
|
}
|
|
|
|
await query(`
|
|
CREATE TABLE zen_posts_category (
|
|
id SERIAL PRIMARY KEY,
|
|
post_type VARCHAR(100) NOT NULL,
|
|
title VARCHAR(255) NOT NULL,
|
|
description TEXT,
|
|
is_active BOOLEAN DEFAULT true,
|
|
created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
|
|
)
|
|
`);
|
|
|
|
await query(`CREATE INDEX idx_zen_posts_category_post_type ON zen_posts_category(post_type)`);
|
|
await query(`CREATE INDEX idx_zen_posts_category_is_active ON zen_posts_category(is_active)`);
|
|
|
|
console.log(`✓ Created table: ${tableName}`);
|
|
return { created: true, tableName };
|
|
}
|
|
|
|
async function createPostsTable() {
|
|
const tableName = 'zen_posts';
|
|
const exists = await tableExists(tableName);
|
|
|
|
if (exists) {
|
|
console.log(`- Table already exists: ${tableName}`);
|
|
return { created: false, tableName };
|
|
}
|
|
|
|
await query(`
|
|
CREATE TABLE zen_posts (
|
|
id SERIAL PRIMARY KEY,
|
|
post_type VARCHAR(100) NOT NULL,
|
|
slug VARCHAR(500) NOT NULL,
|
|
data JSONB NOT NULL DEFAULT '{}',
|
|
category_id INTEGER REFERENCES zen_posts_category(id) ON DELETE SET NULL,
|
|
created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
|
|
UNIQUE(post_type, slug)
|
|
)
|
|
`);
|
|
|
|
await query(`CREATE INDEX idx_zen_posts_post_type ON zen_posts(post_type)`);
|
|
await query(`CREATE INDEX idx_zen_posts_post_type_slug ON zen_posts(post_type, slug)`);
|
|
await query(`CREATE INDEX idx_zen_posts_category_id ON zen_posts(category_id)`);
|
|
await query(`CREATE INDEX idx_zen_posts_data_gin ON zen_posts USING GIN (data)`);
|
|
|
|
console.log(`✓ Created table: ${tableName}`);
|
|
return { created: true, tableName };
|
|
}
|
|
|
|
async function createPostsRelationsTable() {
|
|
const tableName = 'zen_posts_relations';
|
|
const exists = await tableExists(tableName);
|
|
|
|
if (exists) {
|
|
console.log(`- Table already exists: ${tableName}`);
|
|
return { created: false, tableName };
|
|
}
|
|
|
|
await query(`
|
|
CREATE TABLE zen_posts_relations (
|
|
id SERIAL PRIMARY KEY,
|
|
post_id INTEGER NOT NULL REFERENCES zen_posts(id) ON DELETE CASCADE,
|
|
field_name VARCHAR(100) NOT NULL,
|
|
related_post_id INTEGER NOT NULL REFERENCES zen_posts(id) ON DELETE CASCADE,
|
|
sort_order INTEGER DEFAULT 0,
|
|
UNIQUE(post_id, field_name, related_post_id)
|
|
)
|
|
`);
|
|
|
|
await query(`CREATE INDEX idx_zen_posts_relations_post_id ON zen_posts_relations(post_id)`);
|
|
await query(`CREATE INDEX idx_zen_posts_relations_related ON zen_posts_relations(related_post_id)`);
|
|
|
|
console.log(`✓ Created table: ${tableName}`);
|
|
return { created: true, tableName };
|
|
}
|
|
|
|
/**
|
|
* Create all posts-related tables.
|
|
* zen_posts_category is only created if at least one type uses the 'category' field.
|
|
* zen_posts_relations is only created if at least one type uses the 'relation' field.
|
|
* @returns {Promise<Object>}
|
|
*/
|
|
export async function createTables() {
|
|
const created = [];
|
|
const skipped = [];
|
|
|
|
const config = getPostsConfig();
|
|
const needsRelations = Object.values(config.types).some(t => t.hasRelations);
|
|
|
|
// zen_posts_category must always be created before zen_posts
|
|
// because zen_posts has a FK reference to it
|
|
console.log('\n--- Posts Categories ---');
|
|
const catResult = await createPostsCategoryTable();
|
|
if (catResult.created) created.push(catResult.tableName);
|
|
else skipped.push(catResult.tableName);
|
|
|
|
console.log('\n--- Posts ---');
|
|
const postResult = await createPostsTable();
|
|
if (postResult.created) created.push(postResult.tableName);
|
|
else skipped.push(postResult.tableName);
|
|
|
|
if (needsRelations) {
|
|
console.log('\n--- Posts Relations ---');
|
|
const relResult = await createPostsRelationsTable();
|
|
if (relResult.created) created.push(relResult.tableName);
|
|
else skipped.push(relResult.tableName);
|
|
}
|
|
|
|
return { created, skipped };
|
|
}
|