mirror of
https://github.com/yanislav-igonin/micrach
synced 2024-12-21 22:02:34 +03:00
Feature - Threads archivation (#4)
* todo * update env var * add new var to config * update GetCount (not archived threads) * wip on threads count check * feat: add get oldest updated at thread * feat: add archivation method for oldest threads * feat: add migrations for posts timefields * feat: now child posts created without updated_at * feat: add threads archivation
This commit is contained in:
parent
9d2703f35a
commit
783e577311
@ -2,4 +2,5 @@ ENV=debug
|
||||
PORT=3000
|
||||
SEED_DB=true
|
||||
IS_RATE_LIMITER_ENABLED=true
|
||||
THREADS_MAX_COUNT=50
|
||||
POSTGRES_URL=postgres://localhost/micrach?pool_max_conns=5
|
@ -2,6 +2,7 @@ package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"strconv"
|
||||
)
|
||||
@ -11,6 +12,7 @@ type AppConfig struct {
|
||||
Port int
|
||||
SeedDb bool
|
||||
IsRateLimiterEnabled bool
|
||||
ThreadsMaxCount int
|
||||
}
|
||||
|
||||
type DbConfig struct {
|
||||
@ -29,7 +31,7 @@ func getAppConfig() AppConfig {
|
||||
}
|
||||
port, err := strconv.Atoi(portString)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("Could not parse %s to int", portString))
|
||||
log.Panicln(fmt.Sprintf("Could not parse %s to int", portString))
|
||||
}
|
||||
|
||||
seedDbString := os.Getenv("SEED_DB")
|
||||
@ -38,11 +40,18 @@ func getAppConfig() AppConfig {
|
||||
isRateLimiterEnabledString := os.Getenv("IS_RATE_LIMITER_ENABLED")
|
||||
isRateLimiterEnabled := isRateLimiterEnabledString == "true"
|
||||
|
||||
threadsMaxCountString := os.Getenv("THREADS_MAX_COUNT")
|
||||
threadsMaxCount, err := strconv.Atoi(threadsMaxCountString)
|
||||
if err != nil {
|
||||
log.Panicln(fmt.Sprintf("Could not parse %s to int", threadsMaxCountString))
|
||||
}
|
||||
|
||||
return AppConfig{
|
||||
Env: env,
|
||||
Port: port,
|
||||
SeedDb: seedDb,
|
||||
IsRateLimiterEnabled: isRateLimiterEnabled,
|
||||
ThreadsMaxCount: threadsMaxCount,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -12,6 +12,7 @@ import (
|
||||
"github.com/dchest/captcha"
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
Config "micrach/config"
|
||||
Db "micrach/db"
|
||||
Repositories "micrach/repositories"
|
||||
Utils "micrach/utils"
|
||||
@ -133,6 +134,28 @@ func CreateThread(c *gin.Context) {
|
||||
}
|
||||
defer conn.Release()
|
||||
|
||||
threadsCount, err := Repositories.Posts.GetCount()
|
||||
if err != nil {
|
||||
log.Println("error:", err)
|
||||
c.HTML(http.StatusInternalServerError, "500.html", nil)
|
||||
return
|
||||
}
|
||||
|
||||
if threadsCount >= Config.App.ThreadsMaxCount {
|
||||
oldestThreadUpdatedAt, err := Repositories.Posts.GetOldestThreadUpdatedAt()
|
||||
if err != nil {
|
||||
log.Println("error:", err)
|
||||
c.HTML(http.StatusInternalServerError, "500.html", nil)
|
||||
return
|
||||
}
|
||||
err = Repositories.Posts.ArchiveThreadsFrom(oldestThreadUpdatedAt)
|
||||
if err != nil {
|
||||
log.Println("error:", err)
|
||||
c.HTML(http.StatusInternalServerError, "500.html", nil)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
tx, err := conn.Begin(context.TODO())
|
||||
if err != nil {
|
||||
log.Println("error:", err)
|
||||
|
@ -33,4 +33,4 @@ CREATE TABLE migrations
|
||||
id INT NOT NULL,
|
||||
name VARCHAR NOT NULL,
|
||||
created_at TIMESTAMP DEFAULT NOW() NOT NULL
|
||||
)
|
||||
)
|
||||
|
9
migrations/3-remove_posts_updated_at_default.sql
Normal file
9
migrations/3-remove_posts_updated_at_default.sql
Normal file
@ -0,0 +1,9 @@
|
||||
ALTER TABLE posts
|
||||
ALTER COLUMN updated_at DROP NOT NULL;
|
||||
|
||||
ALTER TABLE posts
|
||||
ALTER COLUMN updated_at DROP DEFAULT;
|
||||
|
||||
UPDATE posts
|
||||
SET updated_at = null
|
||||
WHERE is_parent != true;
|
5
migrations/4-posts_timefields_now_with_timezone.sql
Normal file
5
migrations/4-posts_timefields_now_with_timezone.sql
Normal file
@ -0,0 +1,5 @@
|
||||
ALTER TABLE posts
|
||||
ALTER COLUMN created_at TYPE timestamptz;
|
||||
|
||||
ALTER TABLE posts
|
||||
ALTER COLUMN updated_at TYPE timestamptz;
|
@ -2,7 +2,9 @@ package repositories
|
||||
|
||||
import (
|
||||
"context"
|
||||
Config "micrach/config"
|
||||
Db "micrach/db"
|
||||
"time"
|
||||
|
||||
"github.com/jackc/pgx/v4"
|
||||
)
|
||||
@ -66,6 +68,7 @@ func (r *PostsRepository) GetCount() (int, error) {
|
||||
WHERE
|
||||
is_parent = true
|
||||
AND is_deleted != true
|
||||
AND is_archived != true
|
||||
`
|
||||
|
||||
row := Db.Pool.QueryRow(context.TODO(), sql)
|
||||
@ -79,19 +82,19 @@ func (r *PostsRepository) GetCount() (int, error) {
|
||||
|
||||
func (r *PostsRepository) Create(p Post) (int, error) {
|
||||
sql := `
|
||||
INSERT INTO posts (is_parent, parent_id, title, text, is_sage)
|
||||
VALUES ($1, $2, $3, $4, $5)
|
||||
INSERT INTO posts (is_parent, parent_id, title, text, is_sage, updated_at)
|
||||
VALUES ($1, $2, $3, $4, $5, $6)
|
||||
RETURNING id
|
||||
`
|
||||
|
||||
var row pgx.Row
|
||||
if p.IsParent {
|
||||
row = Db.Pool.QueryRow(
|
||||
context.TODO(), sql, p.IsParent, nil, p.Title, p.Text, p.IsSage,
|
||||
context.TODO(), sql, p.IsParent, nil, p.Title, p.Text, p.IsSage, time.Now(),
|
||||
)
|
||||
} else {
|
||||
row = Db.Pool.QueryRow(
|
||||
context.TODO(), sql, p.IsParent, p.ParentID, p.Title, p.Text, p.IsSage,
|
||||
context.TODO(), sql, p.IsParent, p.ParentID, p.Title, p.Text, p.IsSage, nil,
|
||||
)
|
||||
}
|
||||
|
||||
@ -165,19 +168,19 @@ func (r *PostsRepository) GetThreadByPostID(ID int) ([]Post, error) {
|
||||
|
||||
func (r *PostsRepository) CreateInTx(tx pgx.Tx, p Post) (int, error) {
|
||||
sql := `
|
||||
INSERT INTO posts (is_parent, parent_id, title, text, is_sage)
|
||||
VALUES ($1, $2, $3, $4, $5)
|
||||
INSERT INTO posts (is_parent, parent_id, title, text, is_sage, updated_at)
|
||||
VALUES ($1, $2, $3, $4, $5, $6)
|
||||
RETURNING id
|
||||
`
|
||||
|
||||
var row pgx.Row
|
||||
if p.IsParent {
|
||||
row = tx.QueryRow(
|
||||
context.TODO(), sql, p.IsParent, nil, p.Title, p.Text, p.IsSage,
|
||||
context.TODO(), sql, p.IsParent, nil, p.Title, p.Text, p.IsSage, time.Now(),
|
||||
)
|
||||
} else {
|
||||
row = tx.QueryRow(
|
||||
context.TODO(), sql, p.IsParent, p.ParentID, p.Title, p.Text, p.IsSage,
|
||||
context.TODO(), sql, p.IsParent, p.ParentID, p.Title, p.Text, p.IsSage, nil,
|
||||
)
|
||||
}
|
||||
|
||||
@ -206,3 +209,38 @@ func (r *PostsRepository) CreateInTx(tx pgx.Tx, p Post) (int, error) {
|
||||
|
||||
return createdPost.ID, nil
|
||||
}
|
||||
|
||||
func (r *PostsRepository) GetOldestThreadUpdatedAt() (time.Time, error) {
|
||||
sql := `
|
||||
SELECT updated_at
|
||||
FROM posts
|
||||
WHERE
|
||||
is_parent = true
|
||||
AND is_deleted != true
|
||||
AND is_archived != true
|
||||
ORDER BY updated_at DESC
|
||||
OFFSET $1 - 1
|
||||
LIMIT 1
|
||||
`
|
||||
|
||||
row := Db.Pool.QueryRow(context.TODO(), sql, Config.App.ThreadsMaxCount)
|
||||
var updatedAt time.Time
|
||||
err := row.Scan(&updatedAt)
|
||||
if err != nil {
|
||||
return time.Time{}, err
|
||||
}
|
||||
return updatedAt, nil
|
||||
}
|
||||
|
||||
func (r *PostsRepository) ArchiveThreadsFrom(t time.Time) error {
|
||||
sql := `
|
||||
UPDATE posts
|
||||
SET is_archived = true
|
||||
WHERE
|
||||
is_archived != true
|
||||
AND updated_at <= $1
|
||||
`
|
||||
|
||||
_, err := Db.Pool.Exec(context.TODO(), sql, t)
|
||||
return err
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
// TODO: move all functions to different packages
|
||||
package utils
|
||||
|
||||
import (
|
||||
|
Loading…
Reference in New Issue
Block a user