diff --git a/examples/nginx/docker-compose.yml b/examples/nginx/docker-compose.yml new file mode 100644 index 00000000..8d4ac391 --- /dev/null +++ b/examples/nginx/docker-compose.yml @@ -0,0 +1,41 @@ +services: + sqlpage: + image: lovasoa/sqlpage:main + volumes: + - sqlpage_socket:/tmp/sqlpage + - ./sqlpage_config:/etc/sqlpage + - ./website:/var/www/ + environment: + - DATABASE_URL=mysql://sqlpage:sqlpage_password@mysql:3306/sqlpage_db + - SQLPAGE_UNIX_SOCKET=/tmp/sqlpage/sqlpage.sock + depends_on: + - mysql + + nginx: + image: nginx:alpine + ports: + - "80:80" + volumes: + - sqlpage_socket:/tmp/sqlpage:ro + - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro + depends_on: + - sqlpage + command: > + sh -c " + adduser -D -u 1000 sqlpage || true && + nginx -g 'daemon off;' + " + + mysql: + image: mysql:8 + environment: + - MYSQL_ROOT_PASSWORD=root_password + - MYSQL_DATABASE=sqlpage_db + - MYSQL_USER=sqlpage + - MYSQL_PASSWORD=sqlpage_password + volumes: + - mysql_data:/var/lib/mysql + +volumes: + mysql_data: + sqlpage_socket: \ No newline at end of file diff --git a/examples/nginx/nginx/nginx.conf b/examples/nginx/nginx/nginx.conf new file mode 100644 index 00000000..23660053 --- /dev/null +++ b/examples/nginx/nginx/nginx.conf @@ -0,0 +1,62 @@ +user sqlpage; +worker_processes auto; + +error_log /var/log/nginx/error.log notice; +pid /var/run/nginx.pid; + +events { + worker_connections 1024; +} + +http { + include /etc/nginx/mime.types; + default_type application/octet-stream; + + log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for"'; + + access_log /var/log/nginx/access.log main; + + sendfile on; + keepalive_timeout 65; + + # Define a rate limiting zone + limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s; + + server { + listen 80; + server_name localhost; + + # Serve static files directly + location /static/ { + alias /var/www/static/; + } + + # Proxy requests to SQLPage + location / { + # Apply rate limiting + limit_req zone=one burst=5; + + # URL rewriting example + rewrite ^/post/([0-9]+)$ /post.sql?id=$1 last; + + proxy_pass http://unix:/tmp/sqlpage/sqlpage.sock; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + + # Enable caching + proxy_cache_valid 200 60m; + proxy_cache_valid 404 10m; + proxy_cache_use_stale error timeout http_500 http_502 http_503 http_504; + + # Enable buffering + proxy_buffering on; + proxy_buffer_size 128k; + proxy_buffers 4 256k; + proxy_busy_buffers_size 256k; + } + } +} \ No newline at end of file diff --git a/examples/nginx/sqlpage_config/migrations/000_init.sql b/examples/nginx/sqlpage_config/migrations/000_init.sql new file mode 100644 index 00000000..00968966 --- /dev/null +++ b/examples/nginx/sqlpage_config/migrations/000_init.sql @@ -0,0 +1,37 @@ +CREATE TABLE users ( + id INT AUTO_INCREMENT PRIMARY KEY, + username VARCHAR(50) UNIQUE NOT NULL, + email VARCHAR(100) UNIQUE NOT NULL, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +CREATE TABLE posts ( + id INT AUTO_INCREMENT PRIMARY KEY, + user_id INT, + title VARCHAR(255) NOT NULL, + content TEXT, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + FOREIGN KEY (user_id) REFERENCES users(id) +); + +CREATE TABLE comments ( + id INT AUTO_INCREMENT PRIMARY KEY, + post_id INT, + user_id INT, + content TEXT, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + FOREIGN KEY (post_id) REFERENCES posts(id), + FOREIGN KEY (user_id) REFERENCES users(id) +); + +INSERT INTO users (username, email) VALUES +('john_doe', 'john@example.com'), +('jane_smith', 'jane@example.com'); + +INSERT INTO posts (user_id, title, content) VALUES +(1, 'First Post', 'This is the content of the first post.'), +(2, 'Hello World', 'Hello everyone! This is my first post.'); + +INSERT INTO comments (post_id, user_id, content) VALUES +(1, 2, 'Great post!'), +(2, 1, 'Welcome to the community!'); diff --git a/examples/nginx/sqlpage_config/sqlpage.json b/examples/nginx/sqlpage_config/sqlpage.json new file mode 100644 index 00000000..9a5d3302 --- /dev/null +++ b/examples/nginx/sqlpage_config/sqlpage.json @@ -0,0 +1,7 @@ +{ + "max_database_pool_connections": 10, + "database_connection_idle_timeout_seconds": 1800, + "max_uploaded_file_size": 10485760, + "compress_responses": false, + "environment": "production" +} \ No newline at end of file diff --git a/examples/nginx/website/add_comment.sql b/examples/nginx/website/add_comment.sql new file mode 100644 index 00000000..2d7db565 --- /dev/null +++ b/examples/nginx/website/add_comment.sql @@ -0,0 +1,2 @@ +INSERT INTO comments (post_id, user_id, content) VALUES ($id, 1, :content); +SELECT 'redirect' as component, '/post/' || $id AS link; \ No newline at end of file diff --git a/examples/nginx/website/index.sql b/examples/nginx/website/index.sql new file mode 100644 index 00000000..42711a57 --- /dev/null +++ b/examples/nginx/website/index.sql @@ -0,0 +1,10 @@ +SELECT 'list' AS component, 'Blog Posts' AS title; + +SELECT + p.title, + u.username AS description, + 'user' AS icon, + '/post/' || p.id AS link +FROM posts p +JOIN users u ON p.user_id = u.id +ORDER BY p.created_at DESC; \ No newline at end of file diff --git a/examples/nginx/website/post.sql b/examples/nginx/website/post.sql new file mode 100644 index 00000000..97e7dba2 --- /dev/null +++ b/examples/nginx/website/post.sql @@ -0,0 +1,46 @@ +-- Display the post content using the card component +SELECT 'card' as component, + 'Post Details' as title, + 1 as columns; +SELECT p.title as title, + u.username as subtitle, + p.content as description, + p.created_at as footer +FROM posts p +JOIN users u ON p.user_id = u.id +WHERE p.id = $id; + +-- Add a divider +SELECT 'divider' as component; + +-- Display comments using the list component +SELECT 'list' as component, + 'Comments' as title; +SELECT u.username as title, + c.content as description, + c.created_at as subtitle, + 'user' as icon, + CASE + WHEN c.user_id = p.user_id THEN 'blue' + ELSE 'gray' + END as color +FROM comments c +JOIN users u ON c.user_id = u.id +JOIN posts p ON c.post_id = p.id +WHERE c.post_id = $id +ORDER BY c.created_at DESC; + +-- Add a divider +SELECT 'divider' as component; + +-- Add a comment form +SELECT 'form' as component, + 'Add a comment' as title, + 'Post comment' as validate, + '/add_comment.sql?id=' || $id as action; + +SELECT 'textarea' as type, + 'content' as name, + 'Your comment' as label, + 'Write your comment here' as placeholder, + true as required;