274 lines
7.8 KiB
Markdown
274 lines
7.8 KiB
Markdown
# Table Creation Scripts Documentation
|
|
|
|
## Overview
|
|
These scripts handle the creation of all database tables for the keyword management system. Each table has its own creation script to maintain modularity and allow for independent testing.
|
|
|
|
## Script Locations
|
|
```
|
|
/bin/table-admin/create-tables/
|
|
├── create-keywords-table.sh
|
|
├── create-campaigns-table.sh
|
|
├── create-landing-pages-table.sh
|
|
├── create-ad-groups-table.sh
|
|
├── create-keyword-assignments-table.sh
|
|
└── create-import-history-table.sh
|
|
```
|
|
|
|
## Keywords Table Script
|
|
|
|
### Location
|
|
`/bin/table-admin/create-tables/create-keywords-table.sh`
|
|
|
|
### SQL Command
|
|
```sql
|
|
CREATE TABLE Keywords (
|
|
keyword_id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
|
|
keyword VARCHAR(255) NOT NULL,
|
|
|
|
-- GKWP Data
|
|
gkwp_search_volume INTEGER,
|
|
gkwp_competition_index INTEGER,
|
|
gkwp_cpc_min DECIMAL(10,2),
|
|
gkwp_cpc_max DECIMAL(10,2),
|
|
gkwp_last_updated TIMESTAMP,
|
|
|
|
-- SEMRush Data
|
|
semrush_search_volume INTEGER,
|
|
semrush_difficulty INTEGER,
|
|
semrush_cpc DECIMAL(10,2),
|
|
semrush_intent VARCHAR(50),
|
|
semrush_last_updated TIMESTAMP,
|
|
|
|
-- Metadata
|
|
first_imported TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
last_updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
-- Case-insensitive unique constraint
|
|
CREATE UNIQUE INDEX unique_lowercase_keyword
|
|
ON Keywords (LOWER(keyword));
|
|
```
|
|
|
|
### Implementation
|
|
```bash
|
|
#!/bin/bash
|
|
|
|
# Load configuration
|
|
source ../../../.database
|
|
|
|
# Set error handling
|
|
set -e
|
|
|
|
# Setup logging
|
|
LOG_DIR="../../../logs"
|
|
LOG_FILE="${LOG_DIR}/$(date +%Y-%m-%d)-create-keywords-table.log"
|
|
|
|
mkdir -p "$LOG_DIR"
|
|
|
|
# Function to log messages
|
|
log_message() {
|
|
echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a "$LOG_FILE"
|
|
}
|
|
|
|
# Check if table exists
|
|
TABLE_EXISTS=$(psql -h "${DB_HOST}" \
|
|
-p "${DB_PORT}" \
|
|
-U "${DB_USER}" \
|
|
-d "${DB_NAME}" \
|
|
-tAc "SELECT to_regclass('public.keywords');")
|
|
|
|
if [ "$TABLE_EXISTS" == "keywords" ]; then
|
|
log_message "Error: Keywords table already exists"
|
|
exit 1
|
|
fi
|
|
|
|
# Create table
|
|
log_message "Creating Keywords table..."
|
|
|
|
psql -h "${DB_HOST}" \
|
|
-p "${DB_PORT}" \
|
|
-U "${DB_USER}" \
|
|
-d "${DB_NAME}" \
|
|
-f "sql/create-keywords-table.sql"
|
|
|
|
# Verify creation
|
|
if [ $? -eq 0 ]; then
|
|
log_message "Keywords table created successfully"
|
|
|
|
# Log table structure
|
|
log_message "Table structure:"
|
|
psql -h "${DB_HOST}" \
|
|
-p "${DB_PORT}" \
|
|
-U "${DB_USER}" \
|
|
-d "${DB_NAME}" \
|
|
-c "\d+ keywords" >> "$LOG_FILE"
|
|
else
|
|
log_message "Error: Failed to create Keywords table"
|
|
exit 1
|
|
fi
|
|
```
|
|
|
|
## Campaigns Table Script
|
|
|
|
### Location
|
|
`/bin/table-admin/create-tables/create-campaigns-table.sh`
|
|
|
|
### SQL Command
|
|
```sql
|
|
CREATE TABLE Campaigns (
|
|
campaign_id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
|
|
campaign_name VARCHAR(255) NOT NULL,
|
|
status VARCHAR(50) NOT NULL DEFAULT 'active',
|
|
start_date DATE,
|
|
end_date DATE,
|
|
budget_daily DECIMAL(10,2),
|
|
notes TEXT,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
CONSTRAINT unique_campaign_name UNIQUE(campaign_name)
|
|
);
|
|
```
|
|
|
|
## Landing Pages Table Script
|
|
|
|
### Location
|
|
`/bin/table-admin/create-tables/create-landing-pages-table.sh`
|
|
|
|
### SQL Command
|
|
```sql
|
|
CREATE TABLE Landing_Pages (
|
|
landing_page_id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
|
|
url VARCHAR(2048) NOT NULL,
|
|
page_name VARCHAR(255) NOT NULL,
|
|
status VARCHAR(50) NOT NULL DEFAULT 'active',
|
|
notes TEXT,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
CONSTRAINT unique_url UNIQUE(url),
|
|
CONSTRAINT unique_page_name UNIQUE(page_name)
|
|
);
|
|
```
|
|
|
|
## Ad Groups Table Script
|
|
|
|
### Location
|
|
`/bin/table-admin/create-tables/create-ad-groups-table.sh`
|
|
|
|
### SQL Command
|
|
```sql
|
|
CREATE TABLE Ad_Groups (
|
|
ad_group_id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
|
|
campaign_id INTEGER NOT NULL,
|
|
landing_page_id INTEGER NOT NULL,
|
|
ad_group_name VARCHAR(255) NOT NULL,
|
|
status VARCHAR(50) NOT NULL DEFAULT 'active',
|
|
notes TEXT,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
CONSTRAINT fk_campaign
|
|
FOREIGN KEY (campaign_id)
|
|
REFERENCES Campaigns(campaign_id),
|
|
CONSTRAINT fk_landing_page
|
|
FOREIGN KEY (landing_page_id)
|
|
REFERENCES Landing_Pages(landing_page_id),
|
|
CONSTRAINT unique_ad_group_name_per_campaign
|
|
UNIQUE(campaign_id, ad_group_name)
|
|
);
|
|
```
|
|
|
|
## Keyword Assignments Table Script
|
|
|
|
### Location
|
|
`/bin/table-admin/create-tables/create-keyword-assignments-table.sh`
|
|
|
|
### SQL Command
|
|
```sql
|
|
CREATE TABLE Keyword_Ad_Group_Assignments (
|
|
keyword_id INTEGER NOT NULL,
|
|
ad_group_id INTEGER NOT NULL,
|
|
status VARCHAR(50) NOT NULL DEFAULT 'active',
|
|
assigned_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
notes TEXT,
|
|
PRIMARY KEY (keyword_id, ad_group_id),
|
|
FOREIGN KEY (keyword_id) REFERENCES Keywords(keyword_id),
|
|
FOREIGN KEY (ad_group_id) REFERENCES Ad_Groups(ad_group_id)
|
|
);
|
|
```
|
|
|
|
## Import History Table Script
|
|
|
|
### Location
|
|
`/bin/table-admin/create-tables/create-import-history-table.sh`
|
|
|
|
### SQL Command
|
|
```sql
|
|
CREATE TABLE Import_History (
|
|
import_id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
|
|
import_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
source_type VARCHAR(50) NOT NULL,
|
|
filename VARCHAR(255),
|
|
original_seed_keyword VARCHAR(255),
|
|
assigned_ad_group_id INTEGER,
|
|
row_count INTEGER,
|
|
success_count INTEGER,
|
|
error_count INTEGER,
|
|
import_status VARCHAR(50) NOT NULL,
|
|
error_details TEXT,
|
|
notes TEXT,
|
|
FOREIGN KEY (assigned_ad_group_id) REFERENCES Ad_Groups(ad_group_id)
|
|
);
|
|
```
|
|
|
|
## Testing
|
|
Located in `/tests/table-admin/create-tables/`
|
|
|
|
Each table has its own test file:
|
|
```
|
|
/tests/table-admin/create-tables/
|
|
├── create-keywords-table.test.sh
|
|
├── create-campaigns-table.test.sh
|
|
├── create-landing-pages-table.test.sh
|
|
├── create-ad-groups-table.test.sh
|
|
├── create-keyword-assignments-table.test.sh
|
|
└── create-import-history-table.test.sh
|
|
```
|
|
|
|
Example test for Keywords table:
|
|
```bash
|
|
#!/bin/bash
|
|
|
|
source ../../utils/test-framework.sh
|
|
|
|
test_keywords_table_creation() {
|
|
# Ensure table doesn't exist
|
|
psql -d "${DB_NAME}" -c "DROP TABLE IF EXISTS Keywords CASCADE;"
|
|
|
|
# Create table
|
|
../bin/table-admin/create-tables/create-keywords-table.sh
|
|
|
|
# Verify table exists
|
|
exists_check=$(psql -tAc "SELECT to_regclass('public.keywords');" "${DB_NAME}")
|
|
assert_equals "$exists_check" "keywords" "Keywords table should exist"
|
|
|
|
# Verify columns
|
|
columns=$(psql -tAc "\d keywords" "${DB_NAME}")
|
|
assert_contains "$columns" "keyword_id" "Should have keyword_id column"
|
|
assert_contains "$columns" "keyword" "Should have keyword column"
|
|
|
|
# Test unique constraint
|
|
psql -d "${DB_NAME}" -c "INSERT INTO Keywords (keyword) VALUES ('Test');"
|
|
error_check=$(psql -d "${DB_NAME}" -c "INSERT INTO Keywords (keyword) VALUES ('TEST');" 2>&1)
|
|
assert_contains "$error_check" "duplicate key value" "Should enforce case-insensitive uniqueness"
|
|
}
|
|
|
|
run_test_suite
|
|
```
|
|
|
|
## Notes
|
|
- Tables must be created in the correct order due to foreign key constraints
|
|
- Each script includes proper error handling and logging
|
|
- Case-insensitive keyword storage is enforced
|
|
- All timestamp fields use timezone-free TIMESTAMP type
|
|
- Status fields use predefined values
|
|
- Each table has appropriate indexes for performance
|