This commit is contained in:
parent
203df76d6c
commit
81134dc0dd
16 changed files with 435 additions and 145 deletions
6
.cargo/config.toml
Normal file
6
.cargo/config.toml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
[build]
|
||||||
|
rustflags = ["--cfg", "uuid_unstable"]
|
||||||
|
|
||||||
|
[target.x86_64-unknown-linux-gnu]
|
||||||
|
linker = "clang"
|
||||||
|
rustflags = ["-Clink-arg=-fuse-ld=mold", "--cfg", "uuid_unstable"]
|
6
Cargo.lock
generated
6
Cargo.lock
generated
|
@ -1830,12 +1830,12 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uuid"
|
name = "uuid"
|
||||||
version = "1.3.4"
|
version = "1.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0fa2982af2eec27de306107c027578ff7f423d65f7250e40ce0fea8f45248b81"
|
checksum = "d023da39d1fde5a8a3fe1f3e01ca9632ada0a63e9797de55a879d6e2236277be"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"atomic",
|
||||||
"getrandom",
|
"getrandom",
|
||||||
"rand",
|
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ tracing = "0.1"
|
||||||
tracing-subscriber = "0.3"
|
tracing-subscriber = "0.3"
|
||||||
tokio = { version = "1.28", features = ["full"] }
|
tokio = { version = "1.28", features = ["full"] }
|
||||||
sqlx = { version = "0.6", features = [ "runtime-tokio-rustls", "postgres", "uuid", "chrono", "macros", "migrate", "json", "offline"] }
|
sqlx = { version = "0.6", features = [ "runtime-tokio-rustls", "postgres", "uuid", "chrono", "macros", "migrate", "json", "offline"] }
|
||||||
uuid = { version = "1.3", features = ["v4", "fast-rng", "serde"] }
|
uuid = { version = "1.4", features = ["v7", "serde", "std"] }
|
||||||
serde = { version = "1" }
|
serde = { version = "1" }
|
||||||
serde_json = { version = "1", features = ["raw_value"] }
|
serde_json = { version = "1", features = ["raw_value"] }
|
||||||
figment = { version = "0.10", features = ["toml", "env", "test"] }
|
figment = { version = "0.10", features = ["toml", "env", "test"] }
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; -- noqa: RF05
|
CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; -- noqa: RF05
|
||||||
|
|
||||||
CREATE TABLE users (
|
CREATE TABLE users (
|
||||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
id UUID PRIMARY KEY,
|
||||||
name VARCHAR UNIQUE NOT NULL,
|
name VARCHAR UNIQUE NOT NULL,
|
||||||
email VARCHAR,
|
email VARCHAR,
|
||||||
password VARCHAR,
|
password VARCHAR,
|
||||||
|
@ -14,7 +14,7 @@ CREATE TABLE users (
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE sites (
|
CREATE TABLE sites (
|
||||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
id UUID PRIMARY KEY,
|
||||||
owner UUID NOT NULL REFERENCES users (id) ON DELETE CASCADE,
|
owner UUID NOT NULL REFERENCES users (id) ON DELETE CASCADE,
|
||||||
name VARCHAR UNIQUE NOT NULL,
|
name VARCHAR UNIQUE NOT NULL,
|
||||||
title VARCHAR NOT NULL,
|
title VARCHAR NOT NULL,
|
||||||
|
@ -25,7 +25,7 @@ CREATE TABLE sites (
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE pages (
|
CREATE TABLE pages (
|
||||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
id UUID PRIMARY KEY,
|
||||||
site UUID NOT NULL REFERENCES sites (id) ON DELETE CASCADE,
|
site UUID NOT NULL REFERENCES sites (id) ON DELETE CASCADE,
|
||||||
author UUID REFERENCES users (id) ON DELETE SET NULL,
|
author UUID REFERENCES users (id) ON DELETE SET NULL,
|
||||||
slug VARCHAR NOT NULL,
|
slug VARCHAR NOT NULL,
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; -- noqa: RF05
|
CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; -- noqa: RF05
|
||||||
|
|
||||||
CREATE TABLE sessions (
|
CREATE TABLE sessions (
|
||||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
id UUID PRIMARY KEY,
|
||||||
actor UUID NOT NULL REFERENCES users (id) ON DELETE CASCADE,
|
actor UUID NOT NULL REFERENCES users (id) ON DELETE CASCADE,
|
||||||
secret VARCHAR NOT NULL,
|
secret VARCHAR NOT NULL,
|
||||||
created_at TIMESTAMP NOT NULL DEFAULT now(),
|
created_at TIMESTAMP NOT NULL DEFAULT now(),
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; -- noqa: RF05
|
CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; -- noqa: RF05
|
||||||
|
|
||||||
CREATE TABLE collections (
|
CREATE TABLE collections (
|
||||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
id UUID PRIMARY KEY,
|
||||||
site UUID NOT NULL REFERENCES sites (id) ON DELETE CASCADE,
|
site UUID NOT NULL REFERENCES sites (id) ON DELETE CASCADE,
|
||||||
slug VARCHAR NOT NULL,
|
slug VARCHAR NOT NULL,
|
||||||
name VARCHAR NOT NULL,
|
name VARCHAR NOT NULL,
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
-- Remove constraint and index (collections_site_slug_unique, collections_site_slug_idx)
|
-- Remove constraint and index
|
||||||
ALTER TABLE collections DROP CONSTRAINT collections_site_slug_unique;
|
ALTER TABLE collections DROP CONSTRAINT collections_site_slug_unique;
|
||||||
|
|
||||||
DROP INDEX IF EXISTS collections_site_slug_unique;
|
DROP INDEX IF EXISTS collections_site_slug_unique;
|
||||||
|
|
431
sqlx-data.json
431
sqlx-data.json
|
@ -1,28 +1,5 @@
|
||||||
{
|
{
|
||||||
"db": "PostgreSQL",
|
"db": "PostgreSQL",
|
||||||
"0e89d76bdba2178afc2fb2c2a5eba0404e68e7a1d26d9fd5f1161f055dad92df": {
|
|
||||||
"describe": {
|
|
||||||
"columns": [
|
|
||||||
{
|
|
||||||
"name": "id",
|
|
||||||
"ordinal": 0,
|
|
||||||
"type_info": "Uuid"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"nullable": [
|
|
||||||
false
|
|
||||||
],
|
|
||||||
"parameters": {
|
|
||||||
"Left": [
|
|
||||||
"Uuid",
|
|
||||||
"Varchar",
|
|
||||||
"Timestamp",
|
|
||||||
"Timestamp"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"query": "INSERT INTO sessions (actor, secret, created_at, expires_at) VALUES ($1, $2, $3, $4) RETURNING id"
|
|
||||||
},
|
|
||||||
"11e96cfd8c2736f13ce55975ea910dd68640f6f14e38a4b3342d514804e3de27": {
|
"11e96cfd8c2736f13ce55975ea910dd68640f6f14e38a4b3342d514804e3de27": {
|
||||||
"describe": {
|
"describe": {
|
||||||
"columns": [],
|
"columns": [],
|
||||||
|
@ -35,20 +12,228 @@
|
||||||
},
|
},
|
||||||
"query": "DELETE FROM sessions WHERE id = $1"
|
"query": "DELETE FROM sessions WHERE id = $1"
|
||||||
},
|
},
|
||||||
"244e021e36237f5e9ce0f17b6eb3ba58d42fe292e7517a33938c5191bc8787e1": {
|
"23f1a1f2aa96a5a23880f330d04f5dc695a148f4aa50b8c76378b68944569e44": {
|
||||||
|
"describe": {
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"name": "author_display_name",
|
||||||
|
"ordinal": 0,
|
||||||
|
"type_info": "Varchar"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "author_username",
|
||||||
|
"ordinal": 1,
|
||||||
|
"type_info": "Varchar"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "slug",
|
||||||
|
"ordinal": 2,
|
||||||
|
"type_info": "Varchar"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "title",
|
||||||
|
"ordinal": 3,
|
||||||
|
"type_info": "Varchar"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "description",
|
||||||
|
"ordinal": 4,
|
||||||
|
"type_info": "Text"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "tags",
|
||||||
|
"ordinal": 5,
|
||||||
|
"type_info": "VarcharArray"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "blocks!: Json<Vec<PostBlock>>",
|
||||||
|
"ordinal": 6,
|
||||||
|
"type_info": "Jsonb"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "created_at",
|
||||||
|
"ordinal": 7,
|
||||||
|
"type_info": "Timestamp"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "modified_at",
|
||||||
|
"ordinal": 8,
|
||||||
|
"type_info": "Timestamp"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "published",
|
||||||
|
"ordinal": 9,
|
||||||
|
"type_info": "Bool"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"nullable": [
|
||||||
|
null,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
false
|
||||||
|
],
|
||||||
|
"parameters": {
|
||||||
|
"Left": [
|
||||||
|
"Text",
|
||||||
|
"Text"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"query": "SELECT\n COALESCE(users.display_name,users.name) as author_display_name,\n users.name as author_username,\n pages.slug,\n pages.title,\n pages.description,\n pages.tags,\n pages.blocks as \"blocks!: Json<Vec<PostBlock>>\",\n pages.created_at,\n pages.modified_at,\n pages.published\n FROM pages \n JOIN\n sites ON site = sites.id\n JOIN\n users ON author = users.id\n WHERE\n slug = $1\n AND sites.name = $2 \n AND pages.deleted_at IS NULL\n AND sites.deleted_at IS NULL"
|
||||||
|
},
|
||||||
|
"28ec2833283df836e457161f44f0fbc75ed37dcc0ba63eb09bf285aae2f7a380": {
|
||||||
"describe": {
|
"describe": {
|
||||||
"columns": [],
|
"columns": [],
|
||||||
"nullable": [],
|
"nullable": [],
|
||||||
"parameters": {
|
"parameters": {
|
||||||
"Left": [
|
"Left": [
|
||||||
"Varchar",
|
"Uuid",
|
||||||
"Uuid",
|
"Uuid",
|
||||||
"Varchar",
|
"Varchar",
|
||||||
|
"Varchar"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"query": "INSERT INTO collections (id, site, slug, name)\n VALUES ($1, $2, $3, $4)"
|
||||||
|
},
|
||||||
|
"29e0259def5c6fdc34c6a18345150d2714736b91c1f3040fcb07d77cbe2552e1": {
|
||||||
|
"describe": {
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"name": "name",
|
||||||
|
"ordinal": 0,
|
||||||
|
"type_info": "Varchar"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "owner",
|
||||||
|
"ordinal": 1,
|
||||||
|
"type_info": "Varchar"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "owner_display_name",
|
||||||
|
"ordinal": 2,
|
||||||
|
"type_info": "Varchar"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "title",
|
||||||
|
"ordinal": 3,
|
||||||
|
"type_info": "Varchar"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "description",
|
||||||
|
"ordinal": 4,
|
||||||
|
"type_info": "Text"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "created_at",
|
||||||
|
"ordinal": 5,
|
||||||
|
"type_info": "Timestamp"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "collections!: Vec<CollectionNameAndSlug>",
|
||||||
|
"ordinal": 6,
|
||||||
|
"type_info": "RecordArray"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"nullable": [
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
null,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
null
|
||||||
|
],
|
||||||
|
"parameters": {
|
||||||
|
"Left": [
|
||||||
"Text"
|
"Text"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"query": "INSERT INTO sites (name, owner, title, description) VALUES ($1, $2, $3, $4)"
|
"query": "SELECT\n sites.name,\n users.name as owner,\n COALESCE(users.display_name,users.name) as owner_display_name,\n title,\n description,\n sites.created_at,\n array_agg(row(collections.slug, collections.name)) as \"collections!: Vec<CollectionNameAndSlug>\"\n FROM sites\n JOIN\n users ON sites.owner = users.id\n JOIN\n collections ON collections.site = sites.id\n WHERE\n sites.name = $1\n AND sites.deleted_at IS NULL\n GROUP BY\n sites.name, users.name, users.display_name, title, description, sites.created_at"
|
||||||
|
},
|
||||||
|
"320625aa3fac73cb43d6a68592767174558ab1a6923d3574ad629d1a1bd0d4a6": {
|
||||||
|
"describe": {
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"name": "author_display_name",
|
||||||
|
"ordinal": 0,
|
||||||
|
"type_info": "Varchar"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "author_username",
|
||||||
|
"ordinal": 1,
|
||||||
|
"type_info": "Varchar"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "slug",
|
||||||
|
"ordinal": 2,
|
||||||
|
"type_info": "Varchar"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "title",
|
||||||
|
"ordinal": 3,
|
||||||
|
"type_info": "Varchar"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "description",
|
||||||
|
"ordinal": 4,
|
||||||
|
"type_info": "Text"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "tags",
|
||||||
|
"ordinal": 5,
|
||||||
|
"type_info": "VarcharArray"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "blocks!: Json<Vec<PostBlock>>",
|
||||||
|
"ordinal": 6,
|
||||||
|
"type_info": "Jsonb"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "created_at",
|
||||||
|
"ordinal": 7,
|
||||||
|
"type_info": "Timestamp"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "modified_at",
|
||||||
|
"ordinal": 8,
|
||||||
|
"type_info": "Timestamp"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "published",
|
||||||
|
"ordinal": 9,
|
||||||
|
"type_info": "Bool"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"nullable": [
|
||||||
|
null,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
false
|
||||||
|
],
|
||||||
|
"parameters": {
|
||||||
|
"Left": [
|
||||||
|
"Uuid",
|
||||||
|
"Uuid",
|
||||||
|
"Timestamp",
|
||||||
|
"Int8"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"query": "SELECT\n COALESCE(users.display_name,users.name) as author_display_name,\n users.name as author_username,\n pages.slug,\n pages.title,\n pages.description,\n pages.tags,\n pages.blocks as \"blocks!: Json<Vec<PostBlock>>\",\n pages.created_at,\n pages.modified_at,\n pages.published\n FROM pages\n JOIN\n users ON author = users.id\n WHERE\n site = $1\n AND $2 = ANY(collections)\n AND pages.deleted_at IS NULL\n AND published = true\n AND pages.created_at <= $3\n ORDER BY created_at DESC\n LIMIT $4\n "
|
||||||
},
|
},
|
||||||
"35deaad55b84124dcba02c555718fe815003e3f50b1c8ee2fc7e540009fa5aef": {
|
"35deaad55b84124dcba02c555718fe815003e3f50b1c8ee2fc7e540009fa5aef": {
|
||||||
"describe": {
|
"describe": {
|
||||||
|
@ -68,23 +253,50 @@
|
||||||
},
|
},
|
||||||
"query": "SELECT CASE WHEN EXISTS(SELECT 1 FROM users) THEN false ELSE true END AS empty;"
|
"query": "SELECT CASE WHEN EXISTS(SELECT 1 FROM users) THEN false ELSE true END AS empty;"
|
||||||
},
|
},
|
||||||
"51786c014e6f0863b0462646121bed527cc5c0bac343974f2d3b049e46c14e72": {
|
"39237d1e40ce33ce386320212a53986cb21949dd07014772a150242caf4fa610": {
|
||||||
"describe": {
|
"describe": {
|
||||||
"columns": [],
|
"columns": [],
|
||||||
"nullable": [],
|
"nullable": [],
|
||||||
"parameters": {
|
"parameters": {
|
||||||
"Left": [
|
"Left": [
|
||||||
|
"Uuid",
|
||||||
|
"Uuid",
|
||||||
|
"Uuid",
|
||||||
|
"Varchar",
|
||||||
"Varchar",
|
"Varchar",
|
||||||
"Text",
|
"Text",
|
||||||
"VarcharArray",
|
"VarcharArray",
|
||||||
"Jsonb",
|
"Jsonb",
|
||||||
"Uuid",
|
"UuidArray",
|
||||||
"Uuid",
|
"Bool"
|
||||||
"Text"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"query": "UPDATE pages SET title = COALESCE($1, title), description = COALESCE($2, description), tags = COALESCE($3, tags), blocks = COALESCE($4, blocks) WHERE author = $5 AND site = $6 AND slug = $7 AND deleted_at IS NULL"
|
"query": "INSERT INTO pages (id, author, site, slug, title, description, tags, blocks, collections, published)\n VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)"
|
||||||
|
},
|
||||||
|
"562254387ad52ad5ee3cf806085873485d6b8a0b372ac59a0796b9f0c8910cf2": {
|
||||||
|
"describe": {
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"name": "id",
|
||||||
|
"ordinal": 0,
|
||||||
|
"type_info": "Uuid"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"nullable": [
|
||||||
|
false
|
||||||
|
],
|
||||||
|
"parameters": {
|
||||||
|
"Left": [
|
||||||
|
"Uuid",
|
||||||
|
"Uuid",
|
||||||
|
"Varchar",
|
||||||
|
"Timestamp",
|
||||||
|
"Timestamp"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"query": "INSERT INTO sessions (id, actor, secret, created_at, expires_at) VALUES ($1, $2, $3, $4, $5) RETURNING id"
|
||||||
},
|
},
|
||||||
"61fcf083e6abcfed9480164f3ed4ff2f396c8041a30df002f6e4af920b41f4e4": {
|
"61fcf083e6abcfed9480164f3ed4ff2f396c8041a30df002f6e4af920b41f4e4": {
|
||||||
"describe": {
|
"describe": {
|
||||||
|
@ -111,24 +323,6 @@
|
||||||
},
|
},
|
||||||
"query": "DELETE FROM sessions WHERE expires_at < $1"
|
"query": "DELETE FROM sessions WHERE expires_at < $1"
|
||||||
},
|
},
|
||||||
"7b294c850a2feba882b52cc479ae943fdd4a3d26278274ea19eb6a3a0393b4ad": {
|
|
||||||
"describe": {
|
|
||||||
"columns": [],
|
|
||||||
"nullable": [],
|
|
||||||
"parameters": {
|
|
||||||
"Left": [
|
|
||||||
"Uuid",
|
|
||||||
"Uuid",
|
|
||||||
"Varchar",
|
|
||||||
"Varchar",
|
|
||||||
"Text",
|
|
||||||
"VarcharArray",
|
|
||||||
"Jsonb"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"query": "INSERT INTO pages (author, site, slug, title, description, tags, blocks) VALUES ($1, $2, $3, $4, $5, $6, $7)"
|
|
||||||
},
|
|
||||||
"7bdb55b060b5e81b50c1bf86cb117215cba7010c91f8384a397efac06a88507d": {
|
"7bdb55b060b5e81b50c1bf86cb117215cba7010c91f8384a397efac06a88507d": {
|
||||||
"describe": {
|
"describe": {
|
||||||
"columns": [],
|
"columns": [],
|
||||||
|
@ -143,6 +337,35 @@
|
||||||
},
|
},
|
||||||
"query": "DELETE FROM pages WHERE author = $1 AND site = $2 AND slug = $3"
|
"query": "DELETE FROM pages WHERE author = $1 AND site = $2 AND slug = $3"
|
||||||
},
|
},
|
||||||
|
"82450bdd6a4a7ac9ee66fb98fd87993b70fa58577876b0761ceac9e31af27b8a": {
|
||||||
|
"describe": {
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"name": "id",
|
||||||
|
"ordinal": 0,
|
||||||
|
"type_info": "Uuid"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "created_at",
|
||||||
|
"ordinal": 1,
|
||||||
|
"type_info": "Timestamp"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"nullable": [
|
||||||
|
false,
|
||||||
|
false
|
||||||
|
],
|
||||||
|
"parameters": {
|
||||||
|
"Left": [
|
||||||
|
"Uuid",
|
||||||
|
"Varchar",
|
||||||
|
"Varchar",
|
||||||
|
"UuidArray"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"query": "INSERT INTO users ( id, name, password, roles )\n VALUES ( $1,$2,$3,$4 ) RETURNING id, created_at"
|
||||||
|
},
|
||||||
"9f37c6f3929ca1bf2a6ec55291d652b216419fd13e27b3d61d23c9cf900c501e": {
|
"9f37c6f3929ca1bf2a6ec55291d652b216419fd13e27b3d61d23c9cf900c501e": {
|
||||||
"describe": {
|
"describe": {
|
||||||
"columns": [
|
"columns": [
|
||||||
|
@ -164,66 +387,6 @@
|
||||||
},
|
},
|
||||||
"query": "UPDATE sessions SET expires_at = $1 WHERE id = $2 RETURNING id"
|
"query": "UPDATE sessions SET expires_at = $1 WHERE id = $2 RETURNING id"
|
||||||
},
|
},
|
||||||
"c04874a0f4ab7409f53ee50ec34679f6b274b350aff39a8710575c54fcaef1e4": {
|
|
||||||
"describe": {
|
|
||||||
"columns": [],
|
|
||||||
"nullable": [],
|
|
||||||
"parameters": {
|
|
||||||
"Left": [
|
|
||||||
"Varchar",
|
|
||||||
"Varchar",
|
|
||||||
"Text",
|
|
||||||
"Text",
|
|
||||||
"Uuid"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"query": "UPDATE sites SET name = COALESCE($1, name), title = COALESCE($2, title), description = COALESCE($3, description), modified_at = NOW() WHERE name = $4 AND owner = $5 AND deleted_at IS NULL"
|
|
||||||
},
|
|
||||||
"c1121a7da8dc099e6eb3ed8d1008a247524f7b953f2d0db674371714f09c6530": {
|
|
||||||
"describe": {
|
|
||||||
"columns": [
|
|
||||||
{
|
|
||||||
"name": "name",
|
|
||||||
"ordinal": 0,
|
|
||||||
"type_info": "Varchar"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "owner",
|
|
||||||
"ordinal": 1,
|
|
||||||
"type_info": "Varchar"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "title",
|
|
||||||
"ordinal": 2,
|
|
||||||
"type_info": "Varchar"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "description",
|
|
||||||
"ordinal": 3,
|
|
||||||
"type_info": "Text"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "created_at",
|
|
||||||
"ordinal": 4,
|
|
||||||
"type_info": "Timestamp"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"nullable": [
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
true,
|
|
||||||
false
|
|
||||||
],
|
|
||||||
"parameters": {
|
|
||||||
"Left": [
|
|
||||||
"Text"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"query": "SELECT sites.name, users.name as owner, title, description, sites.created_at FROM sites JOIN users ON sites.owner = users.id WHERE sites.name = $1 AND sites.deleted_at IS NULL"
|
|
||||||
},
|
|
||||||
"c567d96c92638902bc90f5fc0aa5bbbe0b6d26607767720a87fdbe67335a0180": {
|
"c567d96c92638902bc90f5fc0aa5bbbe0b6d26607767720a87fdbe67335a0180": {
|
||||||
"describe": {
|
"describe": {
|
||||||
"columns": [
|
"columns": [
|
||||||
|
@ -335,6 +498,22 @@
|
||||||
},
|
},
|
||||||
"query": "DELETE FROM sites WHERE name = $1 AND owner = $2"
|
"query": "DELETE FROM sites WHERE name = $1 AND owner = $2"
|
||||||
},
|
},
|
||||||
|
"d0005084c0ae3939460c3c727b29899c65a05e53fbc477cdda9665e7f243d5e9": {
|
||||||
|
"describe": {
|
||||||
|
"columns": [],
|
||||||
|
"nullable": [],
|
||||||
|
"parameters": {
|
||||||
|
"Left": [
|
||||||
|
"Varchar",
|
||||||
|
"Varchar",
|
||||||
|
"Text",
|
||||||
|
"Text",
|
||||||
|
"Uuid"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"query": "UPDATE sites SET\n name = COALESCE($1, name),\n title = COALESCE($2, title),\n description = COALESCE($3, description),\n modified_at = NOW()\n WHERE\n name = $4\n AND owner = $5\n AND deleted_at IS NULL"
|
||||||
|
},
|
||||||
"d9649c375db5825adda3b91c52468235fd9c361b827df64350c7e65bca0f00b4": {
|
"d9649c375db5825adda3b91c52468235fd9c361b827df64350c7e65bca0f00b4": {
|
||||||
"describe": {
|
"describe": {
|
||||||
"columns": [],
|
"columns": [],
|
||||||
|
@ -349,33 +528,49 @@
|
||||||
},
|
},
|
||||||
"query": "UPDATE pages SET deleted_at = NOW() WHERE author = $1 AND site = $2 AND slug = $3 AND deleted_at IS NULL"
|
"query": "UPDATE pages SET deleted_at = NOW() WHERE author = $1 AND site = $2 AND slug = $3 AND deleted_at IS NULL"
|
||||||
},
|
},
|
||||||
"f054746ab3092a8671604c9388e02220d62d337e9d199fa9102c0363a72f6940": {
|
"e9f521d288a92f1e70b4de35b0d75792007d910ee65e2782eee4a3cdd30560a0": {
|
||||||
"describe": {
|
"describe": {
|
||||||
"columns": [
|
"columns": [
|
||||||
{
|
{
|
||||||
"name": "id",
|
"name": "id",
|
||||||
"ordinal": 0,
|
"ordinal": 0,
|
||||||
"type_info": "Uuid"
|
"type_info": "Uuid"
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "created_at",
|
|
||||||
"ordinal": 1,
|
|
||||||
"type_info": "Timestamp"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"nullable": [
|
"nullable": [
|
||||||
false,
|
|
||||||
false
|
false
|
||||||
],
|
],
|
||||||
"parameters": {
|
"parameters": {
|
||||||
"Left": [
|
"Left": [
|
||||||
|
"Uuid",
|
||||||
"Varchar",
|
"Varchar",
|
||||||
|
"Uuid",
|
||||||
"Varchar",
|
"Varchar",
|
||||||
"UuidArray"
|
"Text"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"query": "INSERT INTO users ( name, password, roles ) VALUES ( $1,$2,$3 ) RETURNING id, created_at"
|
"query": "INSERT INTO sites (id, name, owner, title, description)\n VALUES ($1, $2, $3, $4, $5) RETURNING id"
|
||||||
|
},
|
||||||
|
"ecbbf6f400e058cd6e8695354d65a1883f974a39e11ac5ba0f7fba408fcf6b2a": {
|
||||||
|
"describe": {
|
||||||
|
"columns": [],
|
||||||
|
"nullable": [],
|
||||||
|
"parameters": {
|
||||||
|
"Left": [
|
||||||
|
"Varchar",
|
||||||
|
"Text",
|
||||||
|
"VarcharArray",
|
||||||
|
"Jsonb",
|
||||||
|
"Uuid",
|
||||||
|
"Uuid",
|
||||||
|
"Text",
|
||||||
|
"UuidArray",
|
||||||
|
"Bool"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"query": "UPDATE pages SET title = COALESCE($1, title), description = COALESCE($2, description), tags = COALESCE($3, tags), blocks = COALESCE($4, blocks), collections = COALESCE($8, collections), published = COALESCE($9, published) WHERE author = $5 AND site = $6 AND slug = $7 AND deleted_at IS NULL"
|
||||||
},
|
},
|
||||||
"f3d0f52ab3c9d7ed46086d21cd88207a75d9f2e2990f3fb721f0e14e1ec52e10": {
|
"f3d0f52ab3c9d7ed46086d21cd88207a75d9f2e2990f3fb721f0e14e1ec52e10": {
|
||||||
"describe": {
|
"describe": {
|
||||||
|
|
|
@ -38,7 +38,8 @@ impl Session {
|
||||||
let expires = now + duration;
|
let expires = now + duration;
|
||||||
let secret = random();
|
let secret = random();
|
||||||
let result = sqlx::query!(
|
let result = sqlx::query!(
|
||||||
"INSERT INTO sessions (actor, secret, created_at, expires_at) VALUES ($1, $2, $3, $4) RETURNING id",
|
"INSERT INTO sessions (id, actor, secret, created_at, expires_at) VALUES ($1, $2, $3, $4, $5) RETURNING id",
|
||||||
|
Uuid::now_v7(),
|
||||||
user_id,
|
user_id,
|
||||||
secret,
|
secret,
|
||||||
now,
|
now,
|
||||||
|
|
|
@ -60,7 +60,9 @@ impl User {
|
||||||
roles: &Vec<Uuid>,
|
roles: &Vec<Uuid>,
|
||||||
) -> Result<Self> {
|
) -> Result<Self> {
|
||||||
let result = sqlx::query!(
|
let result = sqlx::query!(
|
||||||
r#"INSERT INTO users ( name, password, roles ) VALUES ( $1,$2,$3 ) RETURNING id, created_at"#,
|
r#"INSERT INTO users ( id, name, password, roles )
|
||||||
|
VALUES ( $1,$2,$3,$4 ) RETURNING id, created_at"#,
|
||||||
|
Uuid::now_v7(),
|
||||||
username,
|
username,
|
||||||
hash(&password)?,
|
hash(&password)?,
|
||||||
roles,
|
roles,
|
||||||
|
|
|
@ -4,6 +4,8 @@ use serde::{Deserialize, Serialize};
|
||||||
use sqlx::{types::Json, FromRow};
|
use sqlx::{types::Json, FromRow};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
use crate::cursor::{AsCursor, CursorList};
|
||||||
|
|
||||||
use super::Error;
|
use super::Error;
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize, FromRow)]
|
#[derive(Deserialize, Serialize, FromRow)]
|
||||||
|
@ -115,15 +117,29 @@ pub struct PostWithAuthor {
|
||||||
pub blocks: Json<Vec<PostBlock>>,
|
pub blocks: Json<Vec<PostBlock>>,
|
||||||
pub created_at: NaiveDateTime,
|
pub created_at: NaiveDateTime,
|
||||||
pub modified_at: Option<NaiveDateTime>,
|
pub modified_at: Option<NaiveDateTime>,
|
||||||
pub deleted_at: Option<NaiveDateTime>,
|
|
||||||
pub published: bool,
|
pub published: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl AsCursor<NaiveDateTime> for PostWithAuthor {
|
||||||
|
fn cursor(&self) -> NaiveDateTime {
|
||||||
|
self.created_at
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
pub trait PostRepository {
|
pub trait PostRepository {
|
||||||
/// Get a post from its slug
|
/// Get a post from its slug
|
||||||
async fn get_post_from_url(&self, site: &str, slug: &str) -> Result<PostWithAuthor, Error>;
|
async fn get_post_from_url(&self, site: &str, slug: &str) -> Result<PostWithAuthor, Error>;
|
||||||
|
|
||||||
|
/// List posts in a collection
|
||||||
|
async fn list_posts_in_collection(
|
||||||
|
&self,
|
||||||
|
site: &Uuid,
|
||||||
|
collection: &Uuid,
|
||||||
|
cursor: Option<NaiveDateTime>,
|
||||||
|
limit: i64,
|
||||||
|
) -> Result<CursorList<PostWithAuthor, NaiveDateTime>, Error>;
|
||||||
|
|
||||||
/// Create a new post
|
/// Create a new post
|
||||||
async fn create_post(
|
async fn create_post(
|
||||||
&self,
|
&self,
|
||||||
|
|
17
src/cursor.rs
Normal file
17
src/cursor.rs
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
pub struct CursorList<T, C> {
|
||||||
|
pub items: Vec<T>,
|
||||||
|
pub next_cursor: Option<C>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait AsCursor<C> {
|
||||||
|
fn cursor(&self) -> C;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: AsCursor<C>, C> CursorList<T, C> {
|
||||||
|
pub fn new(items: Vec<T>, limit: usize) -> Self {
|
||||||
|
CursorList {
|
||||||
|
next_cursor: items.get(limit - 1).map(|x| x.cursor()),
|
||||||
|
items,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -15,7 +15,9 @@ impl CollectionRepository for Database {
|
||||||
|
|
||||||
for (slug, name) in DEFAULT_COLLECTIONS {
|
for (slug, name) in DEFAULT_COLLECTIONS {
|
||||||
sqlx::query!(
|
sqlx::query!(
|
||||||
r#"INSERT INTO collections (site, slug, name) VALUES ($1, $2, $3)"#,
|
r#"INSERT INTO collections (id, site, slug, name)
|
||||||
|
VALUES ($1, $2, $3, $4)"#,
|
||||||
|
Uuid::now_v7(),
|
||||||
site,
|
site,
|
||||||
slug,
|
slug,
|
||||||
name
|
name
|
||||||
|
|
|
@ -1,19 +1,66 @@
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
|
use chrono::NaiveDateTime;
|
||||||
use content::post::PostBlock;
|
use content::post::PostBlock;
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
use sqlx::types::Json;
|
use sqlx::types::Json;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
use crate::content::{
|
use crate::{
|
||||||
|
content::{
|
||||||
self,
|
self,
|
||||||
post::{CreatePostData, PostRepository, PostWithAuthor, UpdatePostData},
|
post::{CreatePostData, PostRepository, PostWithAuthor, UpdatePostData},
|
||||||
Error,
|
Error,
|
||||||
|
},
|
||||||
|
cursor::CursorList,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::Database;
|
use super::Database;
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl PostRepository for Database {
|
impl PostRepository for Database {
|
||||||
|
async fn list_posts_in_collection(
|
||||||
|
&self,
|
||||||
|
site: &Uuid,
|
||||||
|
collection: &Uuid,
|
||||||
|
from: Option<NaiveDateTime>,
|
||||||
|
limit: i64,
|
||||||
|
) -> Result<CursorList<PostWithAuthor, NaiveDateTime>, Error> {
|
||||||
|
let posts = sqlx::query_as!(
|
||||||
|
PostWithAuthor,
|
||||||
|
r#"SELECT
|
||||||
|
COALESCE(users.display_name,users.name) as author_display_name,
|
||||||
|
users.name as author_username,
|
||||||
|
pages.slug,
|
||||||
|
pages.title,
|
||||||
|
pages.description,
|
||||||
|
pages.tags,
|
||||||
|
pages.blocks as "blocks!: Json<Vec<PostBlock>>",
|
||||||
|
pages.created_at,
|
||||||
|
pages.modified_at,
|
||||||
|
pages.published
|
||||||
|
FROM pages
|
||||||
|
JOIN
|
||||||
|
users ON author = users.id
|
||||||
|
WHERE
|
||||||
|
site = $1
|
||||||
|
AND $2 = ANY(collections)
|
||||||
|
AND pages.deleted_at IS NULL
|
||||||
|
AND published = true
|
||||||
|
AND pages.created_at <= $3
|
||||||
|
ORDER BY created_at DESC
|
||||||
|
LIMIT $4
|
||||||
|
"#,
|
||||||
|
site,
|
||||||
|
collection,
|
||||||
|
from.unwrap_or_else(|| NaiveDateTime::MAX),
|
||||||
|
limit
|
||||||
|
)
|
||||||
|
.fetch_all(&self.pool)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Ok(CursorList::new(posts, limit as usize))
|
||||||
|
}
|
||||||
|
|
||||||
async fn get_post_from_url(
|
async fn get_post_from_url(
|
||||||
&self,
|
&self,
|
||||||
site: &str,
|
site: &str,
|
||||||
|
@ -31,7 +78,6 @@ impl PostRepository for Database {
|
||||||
pages.blocks as "blocks!: Json<Vec<PostBlock>>",
|
pages.blocks as "blocks!: Json<Vec<PostBlock>>",
|
||||||
pages.created_at,
|
pages.created_at,
|
||||||
pages.modified_at,
|
pages.modified_at,
|
||||||
pages.deleted_at,
|
|
||||||
pages.published
|
pages.published
|
||||||
FROM pages
|
FROM pages
|
||||||
JOIN
|
JOIN
|
||||||
|
@ -62,7 +108,9 @@ impl PostRepository for Database {
|
||||||
data: CreatePostData,
|
data: CreatePostData,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
sqlx::query!(
|
sqlx::query!(
|
||||||
"INSERT INTO pages (author, site, slug, title, description, tags, blocks, collections, published) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)",
|
"INSERT INTO pages (id, author, site, slug, title, description, tags, blocks, collections, published)
|
||||||
|
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)",
|
||||||
|
Uuid::now_v7(),
|
||||||
owner,
|
owner,
|
||||||
site,
|
site,
|
||||||
data.slug,
|
data.slug,
|
||||||
|
|
|
@ -69,7 +69,9 @@ impl SiteRepository for Database {
|
||||||
|
|
||||||
async fn create_site(&self, owner: &Uuid, options: CreateSiteData) -> Result<Uuid, Error> {
|
async fn create_site(&self, owner: &Uuid, options: CreateSiteData) -> Result<Uuid, Error> {
|
||||||
let result = sqlx::query!(
|
let result = sqlx::query!(
|
||||||
"INSERT INTO sites (name, owner, title, description) VALUES ($1, $2, $3, $4) RETURNING id",
|
"INSERT INTO sites (id, name, owner, title, description)
|
||||||
|
VALUES ($1, $2, $3, $4, $5) RETURNING id",
|
||||||
|
Uuid::now_v7(),
|
||||||
options.name,
|
options.name,
|
||||||
owner,
|
owner,
|
||||||
options.title,
|
options.title,
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
mod auth;
|
mod auth;
|
||||||
mod builtins;
|
mod builtins;
|
||||||
mod content;
|
mod content;
|
||||||
|
mod cursor;
|
||||||
mod database;
|
mod database;
|
||||||
mod http;
|
mod http;
|
||||||
mod routes;
|
mod routes;
|
||||||
|
|
Loading…
Reference in a new issue