mirror of
https://codeberg.org/JasterV/sentences-crud.git
synced 2026-04-26 18:10:05 +00:00
sentences model done
This commit is contained in:
parent
e557ff9a06
commit
c36552bd46
17 changed files with 145 additions and 13 deletions
|
|
@ -0,0 +1 @@
|
||||||
|
API_SECRET=
|
||||||
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -124,4 +124,6 @@ dist
|
||||||
|
|
||||||
.firebase.json
|
.firebase.json
|
||||||
|
|
||||||
|
.env
|
||||||
|
|
||||||
# End of https://www.toptal.com/developers/gitignore/api/node
|
# End of https://www.toptal.com/developers/gitignore/api/node
|
||||||
|
|
|
||||||
|
|
@ -21,19 +21,20 @@ const DATA_FILE_PATH = 'scripts/sentences.jsonl.txt';
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log('Reading sentences.jsonl.txt')
|
console.log('Reading sentences.jsonl.txt')
|
||||||
|
console.log('Importing data to firebase...')
|
||||||
|
|
||||||
rl.on('line', async (line) => {
|
rl.on('line', async (line) => {
|
||||||
const sentence = JSON.parse(line)
|
const sentence = JSON.parse(line)
|
||||||
const sentencesRef = db.collection('sentences');
|
const sentencesRef = db.collection('sentences');
|
||||||
const categoriesRef = db.collection('categories');
|
const entry = Object.entries(sentence.cats).find((elem) => elem['1'] == 1)
|
||||||
|
if(!entry) {
|
||||||
const result = await sentencesRef.add({
|
console.log('Sentence: ', sentence, ' does not have a category')
|
||||||
text: sentence.text
|
return
|
||||||
})
|
}
|
||||||
|
await sentencesRef.add({
|
||||||
await categoriesRef.add({
|
text: sentence.text,
|
||||||
sentenceId: result.id,
|
category: entry['0']
|
||||||
...sentence.cats
|
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
console.log('Done!')
|
||||||
})();
|
})();
|
||||||
|
|
|
||||||
2
src/@types/global.d.ts
vendored
2
src/@types/global.d.ts
vendored
|
|
@ -1,5 +1,7 @@
|
||||||
import config from '../config'
|
import config from '../config'
|
||||||
|
import db from '../db'
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
export type Config = typeof config
|
export type Config = typeof config
|
||||||
|
export type DB = typeof db
|
||||||
}
|
}
|
||||||
|
|
|
||||||
0
src/api/controllers/getSentenceController.ts
Normal file
0
src/api/controllers/getSentenceController.ts
Normal file
0
src/api/controllers/listSentencesController.ts
Normal file
0
src/api/controllers/listSentencesController.ts
Normal file
0
src/api/controllers/updateSentenceController.ts
Normal file
0
src/api/controllers/updateSentenceController.ts
Normal file
19
src/api/middlewares/authMiddleware.ts
Normal file
19
src/api/middlewares/authMiddleware.ts
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
import { Request, Response, NextFunction } from 'express'
|
||||||
|
|
||||||
|
export default (secret: string) => {
|
||||||
|
return (req: Request, res: Response, next: NextFunction) => {
|
||||||
|
const authHeader = req.header('Authorization')
|
||||||
|
if (!authHeader) return res.status(401).json({
|
||||||
|
success: false,
|
||||||
|
msg: 'Unauthorized'
|
||||||
|
})
|
||||||
|
const token = authHeader.split('Bearer ')[1]
|
||||||
|
if(token !== secret) {
|
||||||
|
return res.status(401).json({
|
||||||
|
success: false,
|
||||||
|
msg: 'Unauthorized'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return next()
|
||||||
|
}
|
||||||
|
}
|
||||||
30
src/api/router.ts
Normal file
30
src/api/router.ts
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
import { Router } from 'express'
|
||||||
|
import config from 'src/config'
|
||||||
|
import authMiddleware from './middlewares/authMiddleware'
|
||||||
|
|
||||||
|
const router = Router()
|
||||||
|
|
||||||
|
router.use(authMiddleware(config.secret))
|
||||||
|
|
||||||
|
router.get('/list', (req, res) => {
|
||||||
|
console.log('hi')
|
||||||
|
})
|
||||||
|
|
||||||
|
router.get('/:id', (req, res) => {
|
||||||
|
console.log('hi')
|
||||||
|
})
|
||||||
|
|
||||||
|
router.post('/', (req, res) => {
|
||||||
|
console.log('hi')
|
||||||
|
})
|
||||||
|
|
||||||
|
router.put('/:id', (req, res) => {
|
||||||
|
console.log('hi')
|
||||||
|
})
|
||||||
|
|
||||||
|
router.delete('/:id', (req, res) => {
|
||||||
|
console.log('hi')
|
||||||
|
})
|
||||||
|
|
||||||
|
export default router
|
||||||
|
|
||||||
|
|
@ -1,11 +1,10 @@
|
||||||
import express from 'express'
|
import express from 'express'
|
||||||
|
import router from './router'
|
||||||
|
|
||||||
const app = express()
|
const app = express()
|
||||||
|
|
||||||
app.use(express.json())
|
app.use(express.json())
|
||||||
|
|
||||||
app.get('/dummy/hi', (_req, res) => {
|
app.use('/api/v1/sentences', router)
|
||||||
res.json({success: true, data: 'Hello, World'})
|
|
||||||
})
|
|
||||||
|
|
||||||
export default app
|
export default app
|
||||||
|
|
@ -5,11 +5,15 @@ dotenv.config()
|
||||||
const {
|
const {
|
||||||
NODE_ENV = "development",
|
NODE_ENV = "development",
|
||||||
PORT = 8080,
|
PORT = 8080,
|
||||||
|
API_SECRET,
|
||||||
} = process.env;
|
} = process.env;
|
||||||
|
|
||||||
|
if(!API_SECRET) throw new Error('API_SECRET required but not found')
|
||||||
|
|
||||||
const config = {
|
const config = {
|
||||||
env: NODE_ENV,
|
env: NODE_ENV,
|
||||||
port: PORT
|
port: PORT,
|
||||||
|
secret: API_SECRET
|
||||||
};
|
};
|
||||||
|
|
||||||
export default config;
|
export default config;
|
||||||
15
src/errors.ts
Normal file
15
src/errors.ts
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
export class ApiError extends Error {
|
||||||
|
constructor(description: string) {
|
||||||
|
super(description)
|
||||||
|
Object.setPrototypeOf(this, new.target.prototype) // restore prototype chain
|
||||||
|
Error.captureStackTrace(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class NotFoundError extends ApiError {
|
||||||
|
constructor(description: string) { super(description) }
|
||||||
|
}
|
||||||
|
|
||||||
|
export class DatabaseError extends ApiError {
|
||||||
|
constructor(description: string) { super(description) }
|
||||||
|
}
|
||||||
10
src/interfaces/queryOptions.ts
Normal file
10
src/interfaces/queryOptions.ts
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
export interface ListSentencesOptions {
|
||||||
|
orderBy?: string,
|
||||||
|
order?: 'asc' | 'desc',
|
||||||
|
page?: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface UpdateSentenceOptions {
|
||||||
|
text?: string,
|
||||||
|
category?: string
|
||||||
|
}
|
||||||
5
src/interfaces/sentence.ts
Normal file
5
src/interfaces/sentence.ts
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
export interface Sentence {
|
||||||
|
id: string,
|
||||||
|
text: string,
|
||||||
|
category: string
|
||||||
|
}
|
||||||
44
src/models/sentencesModel.ts
Normal file
44
src/models/sentencesModel.ts
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
import { NotFoundError } from "src/errors";
|
||||||
|
import { ListSentencesOptions, UpdateSentenceOptions } from "src/interfaces/queryOptions"
|
||||||
|
import { Sentence } from "src/interfaces/sentence"
|
||||||
|
|
||||||
|
const model = (db: DB) => {
|
||||||
|
const PAGE_LIMIT = 20
|
||||||
|
|
||||||
|
async function getSentence(id: string): Promise<Sentence> {
|
||||||
|
const sentenceRaw = await db.collection('sentence').doc(id).get();
|
||||||
|
if (!sentenceRaw.exists) throw new NotFoundError(`Sentence with id ${id} not found`)
|
||||||
|
const sentence: Sentence = { id, ...sentenceRaw.data() } as Sentence
|
||||||
|
return sentence
|
||||||
|
}
|
||||||
|
|
||||||
|
async function listSentence(options?: ListSentencesOptions): Promise<Sentence[]> {
|
||||||
|
const { page = 0, orderBy = null, order = 'desc' } = options || {}
|
||||||
|
const sentences: Sentence[] = []
|
||||||
|
let query = db.collection('sentences');
|
||||||
|
// order by property
|
||||||
|
if (orderBy) query = query.orderBy(orderBy, order) as any;
|
||||||
|
// query and return
|
||||||
|
const rawResult = await query.startAt(page * PAGE_LIMIT).limit(PAGE_LIMIT).get()
|
||||||
|
rawResult.forEach((doc) => sentences.push({ id: doc.id, ...doc.data() } as Sentence))
|
||||||
|
return sentences
|
||||||
|
}
|
||||||
|
|
||||||
|
async function deleteSentence(id: string): Promise<string> {
|
||||||
|
const sentenceRaw = await db.collection('sentence').doc(id).get();
|
||||||
|
if (!sentenceRaw.exists) throw new NotFoundError(`Sentence with id ${id} not found`)
|
||||||
|
await sentenceRaw.ref.delete();
|
||||||
|
return id
|
||||||
|
}
|
||||||
|
|
||||||
|
async function updateSentence(id: string, data: UpdateSentenceOptions): Promise<Sentence> {
|
||||||
|
const sentenceRaw = await db.collection('sentence').doc(id).get();
|
||||||
|
if (!sentenceRaw.exists) throw new NotFoundError(`Sentence with id ${id} not found`)
|
||||||
|
await sentenceRaw.ref.update(data);
|
||||||
|
return { id, ...sentenceRaw.data() } as Sentence
|
||||||
|
}
|
||||||
|
|
||||||
|
return { getSentence, listSentence, deleteSentence, updateSentence }
|
||||||
|
}
|
||||||
|
|
||||||
|
export default model
|
||||||
Loading…
Reference in a new issue