Skip to content

Commit 651085a

Browse files
committed
Do some trimming
1 parent 023127c commit 651085a

26 files changed

+322
-1288
lines changed

.dockerignore

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
db-data/
1+
/db-data
22
.git
33
.gitattributes
44
.gitignore

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -106,3 +106,5 @@ venv.bak/
106106
.mypy_cache/
107107

108108
.env
109+
110+
db-data/
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
"""remove_blogs
2+
3+
Revision ID: 13d2afe94e48
4+
Revises: 6a56c28c6bf1
5+
Create Date: 2022-09-06 17:29:55.189057
6+
7+
"""
8+
from alembic import op
9+
import sqlalchemy as sa
10+
from sqlalchemy_searchable import drop_trigger
11+
import sqlalchemy_utils
12+
from sqlalchemy.dialects import postgresql
13+
14+
# revision identifiers, used by Alembic.
15+
revision = '13d2afe94e48'
16+
down_revision = '6a56c28c6bf1'
17+
branch_labels = None
18+
depends_on = None
19+
20+
21+
def upgrade():
22+
# ### commands auto generated by Alembic - please adjust! ###
23+
conn = op.get_bind()
24+
drop_trigger(conn, "blogs", "search_vector")
25+
op.drop_index('blogs_tags_array_idx', table_name='blogs')
26+
op.drop_table('blogs')
27+
# ### end Alembic commands ###
28+
29+
30+
def downgrade():
31+
# ### commands auto generated by Alembic - please adjust! ###
32+
op.create_table('blogs',
33+
sa.Column('id', sa.INTEGER(), autoincrement=True, nullable=False),
34+
sa.Column('title', sa.TEXT(), autoincrement=False, nullable=False),
35+
sa.Column('slug', sa.TEXT(), autoincrement=False, nullable=False),
36+
sa.Column('tags', postgresql.ARRAY(sa.TEXT()), autoincrement=False, nullable=False),
37+
sa.Column('content', sa.TEXT(), autoincrement=False, nullable=False),
38+
sa.Column('creation_date', postgresql.TIMESTAMP(), server_default=sa.text('now()'), autoincrement=False, nullable=False),
39+
sa.Column('edit_date', postgresql.TIMESTAMP(), server_default=sa.text('now()'), autoincrement=False, nullable=False),
40+
sa.Column('search_vector', postgresql.TSVECTOR(), autoincrement=False, nullable=True),
41+
sa.Column('author_id', sa.BIGINT(), autoincrement=False, nullable=True),
42+
sa.CheckConstraint("slug <> ''::text", name='blogs_slug_nonempty'),
43+
sa.ForeignKeyConstraint(['author_id'], ['users.discord_id'], name='blogs_author_id_fkey', ondelete='SET NULL'),
44+
sa.PrimaryKeyConstraint('id', name='blogs_pkey'),
45+
sa.UniqueConstraint('slug', name='blogs_slug_key'),
46+
sa.UniqueConstraint('title', name='blogs_title_key')
47+
)
48+
op.create_index('blogs_tags_array_idx', 'blogs', ['tags'], unique=False)
49+
# ### end Alembic commands ###
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
"""instantiate_search_fns
2+
3+
Revision ID: 6a56c28c6bf1
4+
Revises: f78a26022069
5+
Create Date: 2022-09-06 17:23:48.327005
6+
7+
"""
8+
from alembic import op
9+
import sqlalchemy as sa
10+
import sqlalchemy_utils
11+
from sqlalchemy_searchable import sql_expressions
12+
13+
14+
# revision identifiers, used by Alembic.
15+
revision = '6a56c28c6bf1'
16+
down_revision = 'f78a26022069'
17+
branch_labels = None
18+
depends_on = None
19+
20+
21+
def upgrade():
22+
conn = op.get_bind()
23+
24+
conn.execute(sql_expressions.statement)
25+
pass
26+
27+
28+
def downgrade():
29+
pass

alembic/versions/98b885be8d35_add_writeup_schema.py

+1-3
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from alembic import op
99
import sqlalchemy as sa
1010
import sqlalchemy_utils
11-
from sqlalchemy_searchable import sync_trigger, sql_expressions
11+
from sqlalchemy_searchable import sync_trigger
1212

1313
# revision identifiers, used by Alembic.
1414
revision = "98b885be8d35"
@@ -48,8 +48,6 @@ def upgrade():
4848
postgresql_using="gin",
4949
)
5050

51-
conn.execute(sql_expressions.statement)
52-
5351
sync_trigger(conn, "writeups", "search_vector", ["title", "content"])
5452
# ### end Alembic commands ###
5553

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
"""remove_todos
2+
3+
Revision ID: f78a26022069
4+
Revises: 276ab5e9da65
5+
Create Date: 2022-09-06 16:25:19.577355
6+
7+
"""
8+
from alembic import op
9+
import sqlalchemy as sa
10+
import sqlalchemy_utils
11+
from sqlalchemy_searchable import sync_trigger
12+
from sqlalchemy.dialects import postgresql
13+
14+
# revision identifiers, used by Alembic.
15+
revision = 'f78a26022069'
16+
down_revision = '276ab5e9da65'
17+
branch_labels = None
18+
depends_on = None
19+
20+
21+
def upgrade():
22+
# ### commands auto generated by Alembic - please adjust! ###
23+
op.drop_table('todos')
24+
25+
conn = op.get_bind()
26+
27+
sync_trigger(conn,
28+
"challenges", "search_vector", ["title", "content"]
29+
)
30+
31+
sync_trigger(conn,
32+
"writeups", "search_vector", ["title", "content"]
33+
)
34+
# ### end Alembic commands ###
35+
36+
37+
def downgrade():
38+
# ### commands auto generated by Alembic - please adjust! ###
39+
op.create_table('todos',
40+
sa.Column('id', sa.INTEGER(), autoincrement=True, nullable=False),
41+
sa.Column('assigned', sa.BIGINT(), autoincrement=False, nullable=True),
42+
sa.Column('started', postgresql.TIMESTAMP(), server_default=sa.text('now()'), autoincrement=False, nullable=False),
43+
sa.Column('deadline', postgresql.TIMESTAMP(), autoincrement=False, nullable=True),
44+
sa.Column('cancelled', sa.BOOLEAN(), server_default=sa.text('false'), autoincrement=False, nullable=False),
45+
sa.Column('completed', postgresql.TIMESTAMP(), autoincrement=False, nullable=True),
46+
sa.Column('content', sa.TEXT(), autoincrement=False, nullable=False),
47+
sa.PrimaryKeyConstraint('id', name='todos_pkey')
48+
)
49+
50+
conn = op.get_bind()
51+
52+
sync_trigger(conn,
53+
"challenges", "search_vector", ["title", "content"]
54+
)
55+
56+
sync_trigger(conn,
57+
"writeups", "search_vector", ["title", "content"]
58+
)
59+
# ### end Alembic commands ###

luhack_bot/__init__.py

+2-8
Original file line numberDiff line numberDiff line change
@@ -43,32 +43,26 @@ def gen_tokens():
4343
)
4444

4545

46-
def export_writeups_and_blog_posts():
46+
def export_writeups():
4747
import asyncio
4848
import json
4949

5050
from luhack_bot.db.helpers import init_db
51-
from luhack_bot.db.models import Writeup, Blog
51+
from luhack_bot.db.models import Writeup
5252

5353
def id(x):
5454
return x
5555

5656
writeup_keys = {"id": id, "author_id": id, "title": id, "slug": id, "tags": id, "content": id, "creation_date": str, "edit_date": str}
57-
blog_keys = {"id": id, "title": id, "slug": id, "tags": id, "content": id, "creation_date": str, "edit_date": str}
5857

5958
def t_w(w):
6059
return {k: f(getattr(w, k)) for k, f in writeup_keys.items()}
6160

62-
def t_b(b):
63-
return {k: f(getattr(b, k)) for k, f in blog_keys.items()}
64-
6561
async def inner():
6662
await init_db()
6763

6864
writeups = await Writeup.query.gino.all()
69-
blogs = await Blog.query.gino.all()
7065

7166
print(json.dumps([t_w(w) for w in writeups]))
72-
print(json.dumps([t_b(b) for b in blogs]))
7367

7468
asyncio.run(inner())

luhack_bot/cogs/challenges.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@
77
import sqlalchemy as sa
88
from discord.ext import commands
99
from gino.loader import ColumnLoader
10-
from sqlalchemy_searchable import search as pg_search
1110
from discord.ext.alternatives import literal_converter as _
1211
from tabulate import tabulate
1312

1413
from luhack_bot import constants
14+
from luhack_bot.db.helpers import text_search
1515
from luhack_bot.db.models import Challenge, CompletedChallenge, User, db
1616
from luhack_bot.utils.checks import is_admin, is_authed
1717

@@ -74,7 +74,7 @@ async def get_challenge(self, title: str) -> Optional[Challenge]:
7474
async def search_challenges(self, search: str) -> List[Challenge]:
7575
"""Search for challenges, return top 3 matching."""
7676
return (
77-
await pg_search(
77+
await text_search(
7878
Challenge.query.where(sa.not_(Challenge.hidden)), search, sort=True
7979
)
8080
.limit(3)

luhack_bot/cogs/writeups.py

+2-3
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,9 @@
77
import discord
88
import sqlalchemy as sa
99
from discord.ext import commands
10-
from sqlalchemy_searchable import search as pg_search
11-
from discord.ext.alternatives import literal_converter
1210

1311
from luhack_bot import constants
12+
from luhack_bot.db.helpers import text_search
1413
from luhack_bot.db.models import Image, Writeup
1514
from luhack_bot.utils.checks import is_authed
1615

@@ -37,7 +36,7 @@ async def get_writeup(self, title: str) -> Optional[Writeup]:
3736

3837
async def search_writeups(self, search: str) -> List[Writeup]:
3938
"""Search for writeups, return top 3 matching."""
40-
return await pg_search(Writeup.query, search, sort=True).limit(3).gino.all()
39+
return await text_search(Writeup.query, search, sort=True).limit(3).gino.all()
4140

4241
def can_edit_writeup(self, writeup: Writeup, user_id: int) -> bool:
4342
return (

luhack_bot/db/helpers.py

+46
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,52 @@
1+
import sqlalchemy as sa
2+
from sqlalchemy_searchable import inspect_search_vectors, search_manager
3+
from sqlalchemy_utils import TSVectorType
4+
15
from luhack_bot.db.models import db
26
from luhack_bot.secrets import db_url
37

48

59
async def init_db():
610
await db.set_bind(db_url)
11+
12+
def inspect_search_vectors(entity):
13+
return [
14+
column
15+
for column
16+
in sa.inspect(entity).columns.values()
17+
if isinstance(column.type, TSVectorType)
18+
]
19+
20+
def text_search(query, search_query, vector=None, regconfig=None, sort=False):
21+
"""
22+
Search given query with full text search.
23+
:param search_query: the search query
24+
:param vector: search vector to use
25+
:param regconfig: postgresql regconfig to be used
26+
:param sort: order results by relevance (quality of hit)
27+
"""
28+
if not search_query.strip():
29+
return query
30+
31+
if vector is None:
32+
entity = query.locate_all_froms()
33+
search_vectors = inspect_search_vectors(entity)
34+
vector = search_vectors[0]
35+
36+
if regconfig is None:
37+
regconfig = search_manager.options['regconfig']
38+
39+
query = query.where(
40+
vector.op('@@')(sa.func.parse_websearch(regconfig, search_query))
41+
)
42+
if sort:
43+
query = query.order_by(
44+
sa.desc(
45+
sa.func.ts_rank_cd(
46+
vector,
47+
sa.func.parse_websearch(search_query)
48+
)
49+
)
50+
)
51+
52+
return query.params(term=search_query)

0 commit comments

Comments
 (0)