mirror of
https://github.com/pawelmalak/snippet-box.git
synced 2025-12-21 13:23:05 +01:00
Search feature. Changed how controller fetches tags
This commit is contained in:
@@ -1,3 +1,8 @@
|
||||
### v1.4 (TBA)
|
||||
- Added search functionality ([#18](https://github.com/pawelmalak/snippet-box/issues/18))
|
||||
- Fixed date parsing bug ([#22](https://github.com/pawelmalak/snippet-box/issues/22))
|
||||
- Minor UI fixes
|
||||
|
||||
### v1.3 (2021-09-30)
|
||||
- Added dark mode ([#7](https://github.com/pawelmalak/snippet-box/issues/7))
|
||||
- Added syntax highlighting ([#14](https://github.com/pawelmalak/snippet-box/issues/14))
|
||||
|
||||
@@ -2,18 +2,10 @@ import { Request, Response, NextFunction } from 'express';
|
||||
import { QueryTypes, Op } from 'sequelize';
|
||||
import { sequelize } from '../db';
|
||||
import { asyncWrapper } from '../middleware';
|
||||
import { SnippetModel, Snippet_TagModel } from '../models';
|
||||
import {
|
||||
ErrorResponse,
|
||||
getTags,
|
||||
tagParser,
|
||||
Logger,
|
||||
createTags
|
||||
} from '../utils';
|
||||
import { SnippetModel, Snippet_TagModel, TagModel } from '../models';
|
||||
import { ErrorResponse, tagParser, Logger, createTags } from '../utils';
|
||||
import { Body, SearchQuery } from '../typescript/interfaces';
|
||||
|
||||
const logger = new Logger('snippets-controller');
|
||||
|
||||
/**
|
||||
* @description Create new snippet
|
||||
* @route /api/snippets
|
||||
@@ -57,24 +49,27 @@ export const createSnippet = asyncWrapper(
|
||||
export const getAllSnippets = asyncWrapper(
|
||||
async (req: Request, res: Response, next: NextFunction): Promise<void> => {
|
||||
const snippets = await SnippetModel.findAll({
|
||||
raw: true
|
||||
});
|
||||
|
||||
await new Promise<void>(async resolve => {
|
||||
try {
|
||||
for await (let snippet of snippets) {
|
||||
const tags = await getTags(+snippet.id);
|
||||
snippet.tags = tags;
|
||||
include: {
|
||||
model: TagModel,
|
||||
as: 'tags',
|
||||
attributes: ['name'],
|
||||
through: {
|
||||
attributes: []
|
||||
}
|
||||
} catch (err) {
|
||||
logger.log('Error while fetching tags', 'ERROR');
|
||||
} finally {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
|
||||
const populatedSnippets = snippets.map(snippet => {
|
||||
const rawSnippet = snippet.get({ plain: true });
|
||||
|
||||
return {
|
||||
...rawSnippet,
|
||||
tags: rawSnippet.tags?.map(tag => tag.name)
|
||||
};
|
||||
});
|
||||
|
||||
res.status(200).json({
|
||||
data: snippets
|
||||
data: populatedSnippets
|
||||
});
|
||||
}
|
||||
);
|
||||
@@ -88,7 +83,14 @@ export const getSnippet = asyncWrapper(
|
||||
async (req: Request, res: Response, next: NextFunction): Promise<void> => {
|
||||
const snippet = await SnippetModel.findOne({
|
||||
where: { id: req.params.id },
|
||||
raw: true
|
||||
include: {
|
||||
model: TagModel,
|
||||
as: 'tags',
|
||||
attributes: ['name'],
|
||||
through: {
|
||||
attributes: []
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (!snippet) {
|
||||
@@ -100,11 +102,14 @@ export const getSnippet = asyncWrapper(
|
||||
);
|
||||
}
|
||||
|
||||
const tags = await getTags(+req.params.id);
|
||||
snippet.tags = tags;
|
||||
const rawSnippet = snippet.get({ plain: true });
|
||||
const populatedSnippet = {
|
||||
...rawSnippet,
|
||||
tags: rawSnippet.tags?.map(tag => tag.name)
|
||||
};
|
||||
|
||||
res.status(200).json({
|
||||
data: snippet
|
||||
data: populatedSnippet
|
||||
});
|
||||
}
|
||||
);
|
||||
@@ -116,6 +121,8 @@ export const getSnippet = asyncWrapper(
|
||||
*/
|
||||
export const updateSnippet = asyncWrapper(
|
||||
async (req: Request, res: Response, next: NextFunction): Promise<void> => {
|
||||
console.log(req.body);
|
||||
|
||||
let snippet = await SnippetModel.findOne({
|
||||
where: { id: req.params.id }
|
||||
});
|
||||
@@ -219,10 +226,20 @@ export const searchSnippets = asyncWrapper(
|
||||
async (req: Request, res: Response, next: NextFunction): Promise<void> => {
|
||||
const { query, tags, languages } = <SearchQuery>req.body;
|
||||
|
||||
console.log(query, tags, languages);
|
||||
// Check if query is empty
|
||||
if (query === '' && !tags.length && !languages.length) {
|
||||
res.status(200).json({
|
||||
data: []
|
||||
});
|
||||
|
||||
const languageFilter =
|
||||
languages.length > 0 ? { [Op.in]: languages } : { [Op.notIn]: languages };
|
||||
return;
|
||||
}
|
||||
|
||||
const languageFilter = languages.length
|
||||
? { [Op.in]: languages }
|
||||
: { [Op.notIn]: languages };
|
||||
|
||||
const tagFilter = tags.length ? { [Op.in]: tags } : { [Op.notIn]: tags };
|
||||
|
||||
const snippets = await SnippetModel.findAll({
|
||||
where: {
|
||||
@@ -237,6 +254,17 @@ export const searchSnippets = asyncWrapper(
|
||||
language: languageFilter
|
||||
}
|
||||
]
|
||||
},
|
||||
include: {
|
||||
model: TagModel,
|
||||
as: 'tags',
|
||||
attributes: ['name'],
|
||||
where: {
|
||||
name: tagFilter
|
||||
},
|
||||
through: {
|
||||
attributes: []
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
15
src/db/associateModels.ts
Normal file
15
src/db/associateModels.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { TagModel, SnippetModel, Snippet_TagModel } from '../models';
|
||||
|
||||
export const associateModels = async () => {
|
||||
TagModel.belongsToMany(SnippetModel, {
|
||||
through: Snippet_TagModel,
|
||||
foreignKey: 'tag_id',
|
||||
as: 'snippets'
|
||||
});
|
||||
|
||||
SnippetModel.belongsToMany(TagModel, {
|
||||
through: Snippet_TagModel,
|
||||
foreignKey: 'snippet_id',
|
||||
as: 'tags'
|
||||
});
|
||||
};
|
||||
@@ -7,6 +7,7 @@ import { errorHandler } from './middleware';
|
||||
|
||||
// Routers
|
||||
import { snippetRouter } from './routes/snippets';
|
||||
import { associateModels } from './db/associateModels';
|
||||
|
||||
// Env config
|
||||
dotenv.config({ path: './src/config/.env' });
|
||||
@@ -32,6 +33,7 @@ app.use(errorHandler);
|
||||
|
||||
(async () => {
|
||||
await connectDB();
|
||||
await associateModels();
|
||||
|
||||
app.listen(PORT, () => {
|
||||
logger.log(
|
||||
|
||||
@@ -8,7 +8,7 @@ export interface Snippet extends Model {
|
||||
code: string;
|
||||
docs: string;
|
||||
isPinned: number;
|
||||
tags?: string[];
|
||||
tags?: { name: string }[];
|
||||
}
|
||||
|
||||
export interface SnippetCreationAttributes
|
||||
|
||||
Reference in New Issue
Block a user