Fixes
This commit is contained in:
parent
cc306f33ef
commit
e33dba1b45
12 changed files with 172 additions and 47 deletions
|
@ -57,7 +57,7 @@ def run_migrations_offline() -> None:
|
||||||
|
|
||||||
|
|
||||||
def do_run_migrations(connection: Connection) -> None:
|
def do_run_migrations(connection: Connection) -> None:
|
||||||
context.configure(connection=connection, target_metadata=target_metadata)
|
context.configure(connection=connection, target_metadata=target_metadata, compare_server_default=True, compare_type=True)
|
||||||
|
|
||||||
with context.begin_transaction():
|
with context.begin_transaction():
|
||||||
context.run_migrations()
|
context.run_migrations()
|
||||||
|
|
28
backend/alembic/versions/9b7ccd38c01a_test.py
Normal file
28
backend/alembic/versions/9b7ccd38c01a_test.py
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
"""test
|
||||||
|
|
||||||
|
Revision ID: 9b7ccd38c01a
|
||||||
|
Revises: dfb99ba1c75e
|
||||||
|
Create Date: 2023-01-03 23:30:42.286979
|
||||||
|
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = '9b7ccd38c01a'
|
||||||
|
down_revision = 'dfb99ba1c75e'
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade() -> None:
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
pass
|
||||||
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade() -> None:
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
pass
|
||||||
|
# ### end Alembic commands ###
|
28
backend/alembic/versions/b16d4a12f55f_test.py
Normal file
28
backend/alembic/versions/b16d4a12f55f_test.py
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
"""test
|
||||||
|
|
||||||
|
Revision ID: b16d4a12f55f
|
||||||
|
Revises: 9b7ccd38c01a
|
||||||
|
Create Date: 2023-01-03 23:33:23.628323
|
||||||
|
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = 'b16d4a12f55f'
|
||||||
|
down_revision = '9b7ccd38c01a'
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade() -> None:
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
pass
|
||||||
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade() -> None:
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
pass
|
||||||
|
# ### end Alembic commands ###
|
34
backend/alembic/versions/d4125430c46f_set_server_default.py
Normal file
34
backend/alembic/versions/d4125430c46f_set_server_default.py
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
"""set server default
|
||||||
|
|
||||||
|
Revision ID: d4125430c46f
|
||||||
|
Revises: e0a3988a875d
|
||||||
|
Create Date: 2023-01-04 00:16:43.307461
|
||||||
|
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = 'd4125430c46f'
|
||||||
|
down_revision = 'e0a3988a875d'
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade() -> None:
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.alter_column('notes', 'checked',
|
||||||
|
existing_type=sa.BOOLEAN(),
|
||||||
|
server_default='f',
|
||||||
|
existing_nullable=False)
|
||||||
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade() -> None:
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.alter_column('notes', 'checked',
|
||||||
|
existing_type=sa.BOOLEAN(),
|
||||||
|
server_default=None,
|
||||||
|
existing_nullable=False)
|
||||||
|
# ### end Alembic commands ###
|
28
backend/alembic/versions/e0a3988a875d_test.py
Normal file
28
backend/alembic/versions/e0a3988a875d_test.py
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
"""test
|
||||||
|
|
||||||
|
Revision ID: e0a3988a875d
|
||||||
|
Revises: b16d4a12f55f
|
||||||
|
Create Date: 2023-01-03 23:43:28.541936
|
||||||
|
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = 'e0a3988a875d'
|
||||||
|
down_revision = 'b16d4a12f55f'
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade() -> None:
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
pass
|
||||||
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade() -> None:
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
pass
|
||||||
|
# ### end Alembic commands ###
|
|
@ -20,7 +20,7 @@ class Note(Base):
|
||||||
|
|
||||||
id = sa.Column(sa.Integer, primary_key=True)
|
id = sa.Column(sa.Integer, primary_key=True)
|
||||||
title = sa.Column(sa.String, nullable=False)
|
title = sa.Column(sa.String, nullable=False)
|
||||||
checked = sa.Column(sa.Boolean, nullable=False, default=False)
|
checked = sa.Column(sa.Boolean, nullable=False, server_default='f')
|
||||||
|
|
||||||
|
|
||||||
__all__ = ['engine', 'Base', 'async_session', 'Note']
|
__all__ = ['engine', 'Base', 'async_session', 'Note']
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
from fastapi import APIRouter, Depends
|
from fastapi import APIRouter, Depends, Response
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
from sqlalchemy import select, update, delete
|
from sqlalchemy import select, update, delete
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
@ -16,20 +16,23 @@ async def get_notes(session: AsyncSession = Depends(get_session)):
|
||||||
return result.scalars().all()
|
return result.scalars().all()
|
||||||
|
|
||||||
|
|
||||||
|
class NoteResponse(BaseModel):
|
||||||
|
id: int
|
||||||
|
title: str
|
||||||
|
checked: bool
|
||||||
|
|
||||||
|
|
||||||
class NoteCreate(BaseModel):
|
class NoteCreate(BaseModel):
|
||||||
title: str
|
title: str
|
||||||
|
|
||||||
|
|
||||||
@router.post("/items/create")
|
@router.post('/items/create', response_model=NoteResponse)
|
||||||
async def create_note(req: NoteCreate, session: AsyncSession = Depends(get_session)):
|
async def create_note(req: NoteCreate, session: AsyncSession = Depends(get_session)):
|
||||||
note = Note(title=req.title)
|
note = Note(title=req.title)
|
||||||
session.add(note)
|
session.add(note)
|
||||||
await session.commit()
|
await session.commit()
|
||||||
return {
|
await session.refresh(note)
|
||||||
"id": note.id,
|
return NoteResponse(id=note.id, title=note.title, checked=note.checked)
|
||||||
"title": note.title,
|
|
||||||
"checked": note.checked
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class NoteUpdateReq(BaseModel):
|
class NoteUpdateReq(BaseModel):
|
||||||
|
@ -38,30 +41,26 @@ class NoteUpdateReq(BaseModel):
|
||||||
checked: bool
|
checked: bool
|
||||||
|
|
||||||
|
|
||||||
@router.put("/items/update")
|
@router.put('/items/update', response_model=NoteResponse)
|
||||||
async def update_note(req: NoteUpdateReq, session: AsyncSession = Depends(get_session)):
|
async def update_note(req: NoteUpdateReq, session: AsyncSession = Depends(get_session)):
|
||||||
await session.execute(
|
await session.execute(
|
||||||
update(Note).where(Note.id == req.id).values(req.__dict__)
|
update(Note).where(Note.id == req.id).values(req.dict())
|
||||||
)
|
)
|
||||||
await session.commit()
|
await session.commit()
|
||||||
return {
|
return NoteResponse(**req.dict())
|
||||||
"id": req.id,
|
|
||||||
"title": req.title,
|
|
||||||
"checked": req.checked
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class NoteDeleteReq(BaseModel):
|
class NoteDeleteReq(BaseModel):
|
||||||
id: int
|
id: int
|
||||||
|
|
||||||
|
|
||||||
@router.delete("/items/delete")
|
@router.delete('/items/delete')
|
||||||
async def delete_note(req: NoteDeleteReq, session: AsyncSession = Depends(get_session)):
|
async def delete_note(req: NoteDeleteReq, session: AsyncSession = Depends(get_session)):
|
||||||
await session.execute(
|
await session.execute(
|
||||||
delete(Note).where(Note.id == req.id)
|
delete(Note).where(Note.id == req.id)
|
||||||
)
|
)
|
||||||
await session.commit()
|
await session.commit()
|
||||||
return 204
|
return Response(None, 204)
|
||||||
|
|
||||||
|
|
||||||
__all__ = ["router"]
|
__all__ = ["router"]
|
||||||
|
|
|
@ -4,42 +4,38 @@ import Item from "./components/Item.vue";
|
||||||
import Edit from "./components/Edit.vue";
|
import Edit from "./components/Edit.vue";
|
||||||
import config from "./config";
|
import config from "./config";
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
|
import INote from "./INote";
|
||||||
|
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
const response = await axios.get(`${config.apiEndpoint}/items`)
|
const response = await axios.get<INote[]>(`${config.apiEndpoint}/items`)
|
||||||
notes.value = response.data
|
notes.value = response.data
|
||||||
id = Math.max(...notes.value.map((note: any) => note.id), 0)
|
|
||||||
currentNote.value.id = id += 1
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const notes = ref<INote[]>([])
|
||||||
|
const editingNote = ref<INote>({id: -1, title: "", checked: false})
|
||||||
|
|
||||||
let id;
|
async function updateNote(note: INote) {
|
||||||
const notes = ref<any[]>([])
|
|
||||||
const currentNote = ref<any>({id: id += 1, title: "", checked: false})
|
|
||||||
|
|
||||||
async function processNote(note: any) {
|
|
||||||
const index = notes.value.findIndex((item) => item.id === note.id)
|
const index = notes.value.findIndex((item) => item.id === note.id)
|
||||||
if (index !== -1) {
|
if (index !== -1) {
|
||||||
await axios.put(`${config.apiEndpoint}/items/update`, note).then((response) => {
|
const resp = await axios.put(`${config.apiEndpoint}/items/update`, note)
|
||||||
notes.value[index] = response.data
|
notes.value[index] = resp.data
|
||||||
})
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
await axios.post(`${config.apiEndpoint}/items/create`, {title: note.title}).then((response) => {
|
const resp = await axios.post(`${config.apiEndpoint}/items/create`, {title: note.title})
|
||||||
notes.value.push(response.data)
|
notes.value.push(resp.data)
|
||||||
})
|
|
||||||
}
|
}
|
||||||
currentNote.value = {id: id += 1, title: "", checked: false}
|
editingNote.value = {id: -1, title: "", checked: false}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async function deleteNote(note: any) {
|
async function deleteNote(note: INote) {
|
||||||
await axios.delete(`${config.apiEndpoint}/items/delete`, {data: {id: note.id}})
|
await axios.delete(`${config.apiEndpoint}/items/delete`, {data: {id: note.id}})
|
||||||
notes.value = notes.value.filter((item) => item.id !== note.id)
|
notes.value = notes.value.filter((item) => item.id !== note.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async function updateChecked(id: any, checked: boolean) {
|
async function updateChecked(id: number, checked: boolean) {
|
||||||
const index = notes.value.findIndex((item) => item.id === id)
|
const index = notes.value.findIndex((item) => item.id === id)
|
||||||
if (index !== -1) {
|
if (index !== -1) {
|
||||||
notes.value[index].checked = checked
|
notes.value[index].checked = checked
|
||||||
|
@ -53,15 +49,15 @@ async function updateChecked(id: any, checked: boolean) {
|
||||||
<item v-for="el in notes"
|
<item v-for="el in notes"
|
||||||
:note="el"
|
:note="el"
|
||||||
:key="el.id"
|
:key="el.id"
|
||||||
@delete="deleteNote"
|
@delete="() => deleteNote(el)"
|
||||||
@edit="(note) => currentNote = note"
|
@edit="() => editingNote = {...el}"
|
||||||
@updateChecked="(checked) => updateChecked(el.id, checked)"
|
@updateChecked="(checked) => updateChecked(el.id, checked)"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<edit
|
<edit
|
||||||
v-bind:note="currentNote"
|
:note="editingNote"
|
||||||
@done="processNote"
|
@done="updateNote"
|
||||||
@updateTitle="(title) => currentNote.title = title"
|
@updateTitle="(title) => editingNote.title = title"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
5
frontend/src/INote.ts
Normal file
5
frontend/src/INote.ts
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
export default interface INote {
|
||||||
|
id: number
|
||||||
|
title: string
|
||||||
|
checked: boolean
|
||||||
|
}
|
|
@ -1,7 +1,9 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
defineProps<{ note: any }>()
|
import INote from '../INote'
|
||||||
|
|
||||||
|
defineProps<{ note: INote }>()
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(e: 'done', note: any): void,
|
(e: 'done', note: INote): void,
|
||||||
(e: 'updateTitle', title: string): void
|
(e: 'updateTitle', title: string): void
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
defineProps<{ note: any }>()
|
import INote from '../INote'
|
||||||
|
|
||||||
|
defineProps<{ note: INote }>()
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(e: 'delete', note: any): void
|
(e: 'delete'): void
|
||||||
(e: 'edit', note: any): void
|
(e: 'edit'): void
|
||||||
(e: 'updateChecked', checked: boolean): void
|
(e: 'updateChecked', checked: boolean): void
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
|
@ -15,8 +17,8 @@
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<input type="checkbox" :checked="note.checked" @change="handleChecked">
|
<input type="checkbox" :checked="note.checked" @change="handleChecked">
|
||||||
<span class="title">{{ note.title }}</span>
|
<span class="title">{{ note.title }}</span>
|
||||||
<div class="btn" @click="$emit('edit', note)"><span><font-awesome-icon icon="fa-solid fa-pen-to-square" /> Edit</span></div>
|
<div class="btn" @click="$emit('edit')"><span><font-awesome-icon icon="fa-solid fa-pen-to-square" /> Edit</span></div>
|
||||||
<div class="btn" @click="$emit('delete', note)"><span><font-awesome-icon icon="fa-solid fa-trash" /> Delete</span></div>
|
<div class="btn" @click="$emit('delete')"><span><font-awesome-icon icon="fa-solid fa-trash" /> Delete</span></div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
3
frontend/src/vite-env.d.ts
vendored
3
frontend/src/vite-env.d.ts
vendored
|
@ -4,4 +4,7 @@ declare module '*.vue' {
|
||||||
import type { DefineComponent } from 'vue'
|
import type { DefineComponent } from 'vue'
|
||||||
const component: DefineComponent<{}, {}, any>
|
const component: DefineComponent<{}, {}, any>
|
||||||
export default component
|
export default component
|
||||||
|
|
||||||
|
export interface Note {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue