Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

A PostgreSQL extension that provides infinite calendar functionality for recurring schedules with exceptions.

License

Notifications You must be signed in to change notification settings

h4kbas/pgcalendar

Repository files navigation

pgcalendar - Infinite Calendar Extension for PostgreSQL

A powerful PostgreSQL extension for managing recurring events with infinite projections, multiple schedule configurations, and exception handling.

Overview

pgcalendar provides a robust system for managing recurring events where:

  • Events represent logical entities (meetings, tasks, etc.)
  • Schedules define non-overlapping time configurations that generate projections
  • Exceptions modify individual instances (cancellations, modifications)
  • Projections are the actual calendar occurrences generated from schedules

Installation

Prerequisites

  • PostgreSQL 12.0 or later
  • PostgreSQL development tools (for building from source)

Method 1: Install from PGXN (Recommended)

pip install pgxnclient
pgxn install pgcalendar

Method 2: Install from Source

# Clone the repository
git clone https://github.com/h4kbas/pgcalendar.git
cd pgcalendar
# Build and install
make
sudo make install
# Create extension in your database
psql -d your_database -c "CREATE EXTENSION pgcalendar;"

Method 3: Manual Installation

# Copy files to PostgreSQL extensions directory
sudo cp pgcalendar.control /usr/share/postgresql/15/extension/
sudo cp pgcalendar.sql /usr/share/postgresql/15/extension/pgcalendar--1.0.1.sql
sudo cp pgcalendar--uninstall.sql /usr/share/postgresql/15/extension/pgcalendar--1.0.1--uninstall.sql
# Create extension in your database
psql -d your_database -c "CREATE EXTENSION pgcalendar;"

Method 4: Direct SQL Installation

# Run SQL file directly (simpler, but not using CREATE EXTENSION)
psql -d your_database -f pgcalendar.sql

Verification

-- Check if extension is installed
SELECT * FROM pg_extension WHERE extname = 'pgcalendar';
-- Test basic functionality
SELECT * FROM pgcalendar.event_calendar LIMIT 5;

Quick Start

-- 1. Create an event
INSERT INTO pgcalendar.events (name, description, category)
VALUES ('Daily Standup', 'Team daily standup meeting', 'meeting');
-- 2. Get the event_id
SELECT event_id FROM pgcalendar.events WHERE name = 'Daily Standup';
-- 3. Create a schedule (replace X with actual event_id)
INSERT INTO pgcalendar.schedules (
 event_id, start_date, end_date, recurrence_type, recurrence_interval
) VALUES (
 X, '2024年01月01日 09:00:00', '2024年01月07日 23:59:59', 'daily', 1
);
-- 4. Get projections
SELECT * FROM pgcalendar.get_event_projections(X, '2024年01月01日'::date, '2024年01月07日'::date);

Usage Examples

Daily Schedule

INSERT INTO pgcalendar.schedules (
 event_id, start_date, end_date, recurrence_type, recurrence_interval
) VALUES (
 1, '2024年01月01日 09:00:00', '2024年01月07日 23:59:59', 'daily', 1
);

Weekly Schedule

INSERT INTO pgcalendar.schedules (
 event_id, start_date, end_date, recurrence_type, recurrence_interval, recurrence_day_of_week
) VALUES (
 1, '2024年01月01日 10:00:00', '2024年12月31日 23:59:59', 'weekly', 1, 1
);
-- recurrence_day_of_week: 0=Sunday, 1=Monday, etc.

Monthly Schedule

INSERT INTO pgcalendar.schedules (
 event_id, start_date, end_date, recurrence_type, recurrence_interval, recurrence_day_of_month
) VALUES (
 1, '2024年01月01日 10:00:00', '2024年12月31日 23:59:59', 'monthly', 1, 15
);
-- recurrence_day_of_month: 1-31

Yearly Schedule

INSERT INTO pgcalendar.schedules (
 event_id, start_date, end_date, recurrence_type, recurrence_interval, recurrence_month, recurrence_day_of_month
) VALUES (
 1, '2024年01月01日 10:00:00', '2030年12月31日 23:59:59', 'yearly', 1, 1, 1
);
-- recurrence_month: 1-12, recurrence_day_of_month: 1-31

Adding Exceptions

-- Cancel a specific occurrence
INSERT INTO pgcalendar.exceptions (
 schedule_id, exception_date, exception_type, notes
) VALUES (
 1, '2024年01月15日', 'cancelled', 'Holiday - meeting cancelled'
);
-- Modify time only
INSERT INTO pgcalendar.exceptions (
 schedule_id, exception_date, exception_type, modified_start_time, modified_end_time, notes
) VALUES (
 1, '2024年01月22日', 'modified', '2024年01月22日 11:00:00', '2024年01月22日 12:00:00', 'Moved to 11 AM'
);
-- Modify date and time
INSERT INTO pgcalendar.exceptions (
 schedule_id, exception_date, exception_type, modified_date, modified_start_time, modified_end_time, notes
) VALUES (
 1, '2024年01月22日', 'modified', '2024年01月23日', '2024年01月23日 14:00:00', '2024年01月23日 15:00:00', 'Moved to next day'
);

Multiple Schedule Configurations

-- First schedule: Daily for first week
INSERT INTO pgcalendar.schedules (
 event_id, start_date, end_date, recurrence_type, recurrence_interval
) VALUES (1, '2024年01月01日 09:00:00', '2024年01月07日 23:59:59', 'daily', 1);
-- Second schedule: Every other day for second week (no overlap!)
INSERT INTO pgcalendar.schedules (
 event_id, start_date, end_date, recurrence_type, recurrence_interval
) VALUES (1, '2024年01月08日 09:00:00', '2024年01月14日 23:59:59', 'daily', 2);

Advanced Functions

Schedule Transition

Safely transition to a new schedule configuration without overlaps:

SELECT pgcalendar.transition_event_schedule(
 p_event_id := 1,
 p_new_start_date := '2024年01月15日 09:00:00',
 p_new_end_date := '2024年01月31日 23:59:59',
 p_recurrence_type := 'weekly',
 p_recurrence_interval := 2,
 p_recurrence_day_of_week := 1,
 p_description := 'Changed to bi-weekly schedule'
);

Overlap Checking

Check if a schedule would overlap with existing schedules:

SELECT pgcalendar.check_schedule_overlap(
 p_event_id := 1,
 p_start_date := '2024年01月05日 09:00:00',
 p_end_date := '2024年01月10日 23:59:59'
);

Querying Projections

Get Projections for an Event

SELECT * FROM pgcalendar.get_event_projections(
 p_event_id := 1,
 p_start_date := '2024年01月01日'::date,
 p_end_date := '2024年01月31日'::date
);

Get All Events with Details

SELECT * FROM pgcalendar.get_events_detailed(
 p_start_date := '2024年01月01日'::date,
 p_end_date := '2024年01月31日'::date
);

Use the Calendar View

SELECT * FROM pgcalendar.event_calendar;

Schema Reference

Tables

  • events - Main event definitions
  • schedules - Non-overlapping schedule configurations
  • exceptions - Individual projection modifications

Functions

  • get_event_projections(event_id, start_date, end_date) - Get projections for specific event
  • get_events_detailed(start_date, end_date) - Get all events with exception handling
  • transition_event_schedule(...) - Safely change schedule configuration
  • check_schedule_overlap(event_id, start_date, end_date) - Validate schedule timing

Views

  • event_calendar - Current year's calendar view

Rules and Constraints

  1. Non-Overlapping Schedules: Schedules for the same event cannot overlap in time (enforced by triggers)
  2. Schedule Hierarchy: Event → Multiple Schedules → Multiple Projections
  3. Exception Handling: Individual projection instances can be cancelled or modified
  4. Recurrence Patterns: Daily, Weekly, Monthly, and Yearly with configurable intervals

Testing

The project includes comprehensive Node.js/TypeScript tests using Jest.

Setup

# Install dependencies
npm install
# Start test database (using Docker)
npm run test:db:start
# Or set environment variables
export PG_HOST=localhost
export PG_PORT=5433
export PG_USER=postgres
export PG_PASSWORD=postgres
export PG_DB=pgcalendar_test

Running Tests

# Run all tests
npm test
# Run with coverage
npm run test:coverage
# Type check
npm run type-check

Test Database Setup

# Start PostgreSQL container
docker run -d --name pgcalendar-test \
 -e POSTGRES_USER=postgres \
 -e POSTGRES_PASSWORD=postgres \
 -e POSTGRES_DB=pgcalendar_test \
 -p 5433:5432 \
 postgres:15
# Install extension
docker exec -i pgcalendar-test psql -U postgres -d pgcalendar_test -f pgcalendar.sql
# Run tests
npm test
# Cleanup
docker stop pgcalendar-test && docker rm pgcalendar-test

Uninstallation

DROP EXTENSION pgcalendar;

Troubleshooting

Extension Not Found

# Check if files are in the right location
ls -la /usr/share/postgresql/*/extension/pgcalendar*
# Verify PostgreSQL version
pg_config --version

Permission Denied

# Fix permissions if needed
sudo chmod 644 /usr/share/postgresql/*/extension/pgcalendar*

Schema Already Exists

DROP SCHEMA IF EXISTS pgcalendar CASCADE;
CREATE EXTENSION pgcalendar;

License

This extension is licensed under the MIT License. See the LICENSE file for details.

Support

AltStyle によって変換されたページ (->オリジナル) /