Add film CRUD operations and integrate Sakila database enhancement

- Implemented Create, Read, Update (PUT/PATCH), and Delete (CRUD) operations for films.
- Added SQL queries for film management (e.g., NextFilmID, InsertFilm, UpdateFilmPut, PatchFilm, and DeleteFilm).
- Updated HTTP handlers to support enhanced film operations, including validation and null handling.
- Refactored category handling logic for cleaner syntax.
- Included HTTP client test samples for film API in `films_crud_test.http`.
This commit is contained in:
siyahas 2025-09-08 16:28:19 +03:00
parent 54e36528bc
commit 5aa6a96b1d
6 changed files with 616 additions and 182 deletions

View file

@ -2,5 +2,6 @@
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
<mapping directory="$PROJECT_DIR$/sakila-sqlite3" vcs="Git" />
</component>
</project>

View file

@ -261,199 +261,307 @@ func RegisterFilmRoutes(r *gin.Engine, db *sql.DB) {
c.JSON(200, res)
})
/*
// Create film
r.POST("/films", func(c *gin.Context) {
var in struct {
FilmID *int64 `json:"film_id"`
Title string `json:"title"`
Description *string `json:"description"`
ReleaseYear *string `json:"release_year"`
LanguageID int64 `json:"language_id"`
OriginalLangID *int64 `json:"original_language_id"`
RentalDuration *int64 `json:"rental_duration"`
RentalRate *float64 `json:"rental_rate"`
Length *int64 `json:"length"`
ReplacementCost *float64 `json:"replacement_cost"`
Rating *string `json:"rating"`
SpecialFeatures *string `json:"special_features"`
}
if err := c.ShouldBindJSON(&in); err != nil {
c.JSON(400, gin.H{"error": err.Error()})
return
}
if strings.TrimSpace(in.Title) == "" || in.LanguageID == 0 {
c.JSON(400, gin.H{"error": "title and language_id are required"})
return
}
f := sq.Film{Title: in.Title, Description: in.Description, ReleaseYear: in.ReleaseYear, LanguageID: in.LanguageID, OriginalLangID: in.OriginalLangID}
if in.RentalDuration != nil {
f.RentalDuration = *in.RentalDuration
} else {
f.RentalDuration = 3
}
if in.RentalRate != nil {
f.RentalRate = *in.RentalRate
} else {
f.RentalRate = 4.99
}
if in.Length != nil {
f.Length = in.Length
}
if in.ReplacementCost != nil {
f.ReplacementCost = *in.ReplacementCost
} else {
f.ReplacementCost = 19.99
}
if in.Rating != nil {
f.Rating = in.Rating
}
if in.SpecialFeatures != nil {
f.SpecialFeatures = in.SpecialFeatures
}
if in.FilmID != nil {
f.FilmID = *in.FilmID
}
created, err := sq.CreateFilm(c, db, &f)
// Create film
r.POST("/films", func(c *gin.Context) {
var in struct {
FilmID *int64 `json:"film_id"`
Title string `json:"title"`
Description *string `json:"description"`
ReleaseYear *string `json:"release_year"`
LanguageID *int64 `json:"language_id"`
OriginalLanguageID *int64 `json:"original_language_id"`
RentalDuration *int64 `json:"rental_duration"`
RentalRate *float64 `json:"rental_rate"`
Length *int64 `json:"length"`
ReplacementCost *float64 `json:"replacement_cost"`
Rating *string `json:"rating"`
SpecialFeatures *string `json:"special_features"`
}
if err := c.ShouldBindJSON(&in); err != nil {
c.JSON(400, gin.H{"error": err.Error()})
return
}
if strings.TrimSpace(in.Title) == "" || in.LanguageID == nil {
c.JSON(400, gin.H{"error": "title and language_id are required"})
return
}
q := sq.New(db)
var id int64
if in.FilmID != nil {
id = *in.FilmID
} else {
var err error
id, err = q.NextFilmID(c)
if err != nil {
c.JSON(400, gin.H{"error": err.Error()})
c.JSON(500, gin.H{"error": err.Error()})
return
}
self := "/films/" + strconv.FormatInt(created.FilmID, 10)
res := hres.New(self)
res.AddCurie()
res.SetState(created)
res.AddLink("self", halgo.Link{Href: self})
res.AddLink("sakila:actors", halgo.Link{Href: self + "/actors"})
c.Header("Content-Type", "application/hal+json")
c.Header("Location", self)
c.JSON(201, res)
}
toNullString := func(p *string) sql.NullString {
if p == nil {
return sql.NullString{Valid: false}
}
return sql.NullString{String: *p, Valid: true}
}
toNullInt := func(p *int64) sql.NullInt64 {
if p == nil {
return sql.NullInt64{Valid: false}
}
return sql.NullInt64{Int64: *p, Valid: true}
}
var desc interface{}
if in.Description != nil {
desc = *in.Description
} else {
desc = nil
}
rentalDuration := int64(3)
if in.RentalDuration != nil {
rentalDuration = *in.RentalDuration
}
rentalRate := 4.99
if in.RentalRate != nil {
rentalRate = *in.RentalRate
}
replacementCost := 19.99
if in.ReplacementCost != nil {
replacementCost = *in.ReplacementCost
}
length := toNullInt(in.Length)
err := q.InsertFilm(c, sq.InsertFilmParams{
FilmID: id,
Title: in.Title,
Description: desc,
ReleaseYear: toNullString(in.ReleaseYear),
LanguageID: *in.LanguageID,
OriginalLanguageID: toNullInt(in.OriginalLanguageID),
RentalDuration: rentalDuration,
RentalRate: rentalRate,
Length: length,
ReplacementCost: replacementCost,
Rating: toNullString(in.Rating),
SpecialFeatures: toNullString(in.SpecialFeatures),
})
if err != nil {
c.JSON(400, gin.H{"error": err.Error()})
return
}
created, err := q.GetFilm(c, id)
if err != nil {
c.JSON(500, gin.H{"error": err.Error()})
return
}
self := "/films/" + strconv.FormatInt(created.FilmID, 10)
res := hres.New(self)
res.AddCurie()
res.SetState(created)
res.AddLink("self", halgo.Link{Href: self})
res.AddLink("sakila:actors", halgo.Link{Href: self + "/actors"})
res.AddLink("sakila:language", halgo.Link{Href: "/languages/" + strconv.FormatInt(created.LanguageID, 10)})
if created.OriginalLanguageID.Valid {
res.AddLink("sakila:original-language", halgo.Link{Href: "/languages/" + strconv.FormatInt(created.OriginalLanguageID.Int64, 10)})
}
c.Header("Content-Type", "application/hal+json")
c.Header("Location", self)
c.JSON(201, res)
})
// Replace film
r.PUT("/films/:id", func(c *gin.Context) {
id, err := strconv.ParseInt(c.Param("id"), 10, 64)
if err != nil {
c.JSON(400, gin.H{"error": "invalid id"})
return
// Replace film (PUT)
r.PUT("/films/:id", func(c *gin.Context) {
id, err := strconv.ParseInt(c.Param("id"), 10, 64)
if err != nil {
c.JSON(400, gin.H{"error": "invalid id"})
return
}
var in struct {
Title string `json:"title"`
Description *string `json:"description"`
ReleaseYear *string `json:"release_year"`
LanguageID int64 `json:"language_id"`
OriginalLanguageID *int64 `json:"original_language_id"`
RentalDuration int64 `json:"rental_duration"`
RentalRate float64 `json:"rental_rate"`
Length *int64 `json:"length"`
ReplacementCost float64 `json:"replacement_cost"`
Rating *string `json:"rating"`
SpecialFeatures *string `json:"special_features"`
}
if err := c.ShouldBindJSON(&in); err != nil {
c.JSON(400, gin.H{"error": err.Error()})
return
}
if strings.TrimSpace(in.Title) == "" {
c.JSON(400, gin.H{"error": "title is required"})
return
}
q := sq.New(db)
toNullString := func(p *string) sql.NullString {
if p == nil {
return sql.NullString{Valid: false}
}
var in struct {
Title string `json:"title"`
Description *string `json:"description"`
ReleaseYear *string `json:"release_year"`
LanguageID int64 `json:"language_id"`
OriginalLangID *int64 `json:"original_language_id"`
RentalDuration *int64 `json:"rental_duration"`
RentalRate *float64 `json:"rental_rate"`
Length *int64 `json:"length"`
ReplacementCost *float64 `json:"replacement_cost"`
Rating *string `json:"rating"`
SpecialFeatures *string `json:"special_features"`
return sql.NullString{String: *p, Valid: true}
}
toNullInt := func(p *int64) sql.NullInt64 {
if p == nil {
return sql.NullInt64{Valid: false}
}
if err := c.ShouldBindJSON(&in); err != nil {
c.JSON(400, gin.H{"error": err.Error()})
return
}
f := sq.Film{Title: in.Title, Description: in.Description, ReleaseYear: in.ReleaseYear, LanguageID: in.LanguageID, OriginalLangID: in.OriginalLangID}
if in.RentalDuration != nil {
f.RentalDuration = *in.RentalDuration
} else {
f.RentalDuration = 3
}
if in.RentalRate != nil {
f.RentalRate = *in.RentalRate
} else {
f.RentalRate = 4.99
}
if in.Length != nil {
f.Length = in.Length
}
if in.ReplacementCost != nil {
f.ReplacementCost = *in.ReplacementCost
} else {
f.ReplacementCost = 19.99
}
if in.Rating != nil {
f.Rating = in.Rating
}
if in.SpecialFeatures != nil {
f.SpecialFeatures = in.SpecialFeatures
}
updated, err := sq.UpdateFilmPut(c, db, id, f)
if err != nil {
if err == sql.ErrNoRows {
c.JSON(404, gin.H{"error": "not found"})
return
}
c.JSON(400, gin.H{"error": err.Error()})
return
}
self := "/films/" + strconv.FormatInt(updated.FilmID, 10)
res := hres.New(self)
res.AddCurie()
res.SetState(updated)
res.AddLink("self", halgo.Link{Href: self})
res.AddLink("sakila:actors", halgo.Link{Href: self + "/actors"})
c.Header("Content-Type", "application/hal+json")
c.JSON(200, res)
return sql.NullInt64{Int64: *p, Valid: true}
}
var desc interface{}
if in.Description != nil {
desc = *in.Description
} else {
desc = nil
}
aff, err := q.UpdateFilmPut(c, sq.UpdateFilmPutParams{
Title: in.Title,
Description: desc,
ReleaseYear: toNullString(in.ReleaseYear),
LanguageID: in.LanguageID,
OriginalLanguageID: toNullInt(in.OriginalLanguageID),
RentalDuration: in.RentalDuration,
RentalRate: in.RentalRate,
Length: toNullInt(in.Length),
ReplacementCost: in.ReplacementCost,
Rating: toNullString(in.Rating),
SpecialFeatures: toNullString(in.SpecialFeatures),
FilmID: id,
})
if err != nil {
c.JSON(400, gin.H{"error": err.Error()})
return
}
if aff == 0 {
c.JSON(404, gin.H{"error": "not found"})
return
}
updated, err := q.GetFilm(c, id)
if err != nil {
c.JSON(500, gin.H{"error": err.Error()})
return
}
self := "/films/" + strconv.FormatInt(updated.FilmID, 10)
res := hres.New(self)
res.AddCurie()
res.SetState(updated)
res.AddLink("self", halgo.Link{Href: self})
res.AddLink("sakila:actors", halgo.Link{Href: self + "/actors"})
res.AddLink("sakila:language", halgo.Link{Href: "/languages/" + strconv.FormatInt(updated.LanguageID, 10)})
if updated.OriginalLanguageID.Valid {
res.AddLink("sakila:original-language", halgo.Link{Href: "/languages/" + strconv.FormatInt(updated.OriginalLanguageID.Int64, 10)})
}
c.Header("Content-Type", "application/hal+json")
c.JSON(200, res)
})
// Patch film
r.PATCH("/films/:id", func(c *gin.Context) {
id, err := strconv.ParseInt(c.Param("id"), 10, 64)
if err != nil {
c.JSON(400, gin.H{"error": "invalid id"})
return
// Patch film
r.PATCH("/films/:id", func(c *gin.Context) {
id, err := strconv.ParseInt(c.Param("id"), 10, 64)
if err != nil {
c.JSON(400, gin.H{"error": "invalid id"})
return
}
var in struct {
Title *string `json:"title"`
Description *string `json:"description"`
ReleaseYear *string `json:"release_year"`
LanguageID *int64 `json:"language_id"`
OriginalLanguageID *int64 `json:"original_language_id"`
RentalDuration *int64 `json:"rental_duration"`
RentalRate *float64 `json:"rental_rate"`
Length *int64 `json:"length"`
ReplacementCost *float64 `json:"replacement_cost"`
Rating *string `json:"rating"`
SpecialFeatures *string `json:"special_features"`
}
if err := c.ShouldBindJSON(&in); err != nil {
c.JSON(400, gin.H{"error": err.Error()})
return
}
q := sq.New(db)
toNullString := func(p *string) sql.NullString {
if p == nil {
return sql.NullString{Valid: false}
}
var in struct {
Title *string `json:"title"`
Description *string `json:"description"`
ReleaseYear *string `json:"release_year"`
LanguageID *int64 `json:"language_id"`
OriginalLangID *int64 `json:"original_language_id"`
RentalDuration *int64 `json:"rental_duration"`
RentalRate *float64 `json:"rental_rate"`
Length *int64 `json:"length"`
ReplacementCost *float64 `json:"replacement_cost"`
Rating *string `json:"rating"`
SpecialFeatures *string `json:"special_features"`
return sql.NullString{String: *p, Valid: true}
}
toNullInt := func(p *int64) sql.NullInt64 {
if p == nil {
return sql.NullInt64{Valid: false}
}
patch := sq.FilmPatch{Title: in.Title, Description: in.Description, ReleaseYear: in.ReleaseYear, LanguageID: in.LanguageID, OriginalLangID: in.OriginalLangID, RentalDuration: in.RentalDuration, RentalRate: in.RentalRate, Length: in.Length, ReplacementCost: in.ReplacementCost, Rating: in.Rating, SpecialFeatures: in.SpecialFeatures}
updated, err := sq.PatchFilm(c, db, id, patch)
if err != nil {
if err == sql.ErrNoRows {
c.JSON(404, gin.H{"error": "not found"})
return
}
c.JSON(400, gin.H{"error": err.Error()})
return
return sql.NullInt64{Int64: *p, Valid: true}
}
toNullFloat := func(p *float64) sql.NullFloat64 {
if p == nil {
return sql.NullFloat64{Valid: false}
}
self := "/films/" + strconv.FormatInt(updated.FilmID, 10)
res := hres.New(self)
res.AddCurie()
res.SetState(updated)
res.AddLink("self", halgo.Link{Href: self})
res.AddLink("sakila:actors", halgo.Link{Href: self + "/actors"})
c.Header("Content-Type", "application/hal+json")
c.JSON(200, res)
return sql.NullFloat64{Float64: *p, Valid: true}
}
var desc interface{}
if in.Description != nil {
desc = *in.Description
} else {
desc = nil
}
aff, err := q.PatchFilm(c, sq.PatchFilmParams{
Title: toNullString(in.Title),
Description: desc,
ReleaseYear: toNullString(in.ReleaseYear),
LanguageID: toNullInt(in.LanguageID),
OriginalLanguageID: toNullInt(in.OriginalLanguageID),
RentalDuration: toNullInt(in.RentalDuration),
RentalRate: toNullFloat(in.RentalRate),
Length: toNullInt(in.Length),
ReplacementCost: toNullFloat(in.ReplacementCost),
Rating: toNullString(in.Rating),
SpecialFeatures: toNullString(in.SpecialFeatures),
FilmID: id,
})
if err != nil {
c.JSON(400, gin.H{"error": err.Error()})
return
}
if aff == 0 {
c.JSON(404, gin.H{"error": "not found"})
return
}
updated, err := q.GetFilm(c, id)
if err != nil {
c.JSON(500, gin.H{"error": err.Error()})
return
}
self := "/films/" + strconv.FormatInt(updated.FilmID, 10)
res := hres.New(self)
res.AddCurie()
res.SetState(updated)
res.AddLink("self", halgo.Link{Href: self})
res.AddLink("sakila:actors", halgo.Link{Href: self + "/actors"})
res.AddLink("sakila:language", halgo.Link{Href: "/languages/" + strconv.FormatInt(updated.LanguageID, 10)})
if updated.OriginalLanguageID.Valid {
res.AddLink("sakila:original-language", halgo.Link{Href: "/languages/" + strconv.FormatInt(updated.OriginalLanguageID.Int64, 10)})
}
c.Header("Content-Type", "application/hal+json")
c.JSON(200, res)
})
// Delete film
r.DELETE("/films/:id", func(c *gin.Context) {
id, err := strconv.ParseInt(c.Param("id"), 10, 64)
if err != nil {
c.JSON(400, gin.H{"error": "invalid id"})
return
}
q := sq.New(db)
aff, err := q.DeleteFilm(c, id)
if err != nil {
c.JSON(400, gin.H{"error": err.Error()})
return
}
if aff == 0 {
c.JSON(404, gin.H{"error": "not found"})
return
}
c.Status(204)
})
// Delete film
r.DELETE("/films/:id", func(c *gin.Context) {
id, err := strconv.ParseInt(c.Param("id"), 10, 64)
if err != nil {
c.JSON(400, gin.H{"error": "invalid id"})
return
}
if err := sq.DeleteFilm(c, db, id); err != nil {
if err == sql.ErrNoRows {
c.JSON(404, gin.H{"error": "not found"})
return
}
c.JSON(400, gin.H{"error": err.Error()})
return
}
c.Status(204)
})
*/
}

View file

@ -0,0 +1,83 @@
### Films API sample requests (IntelliJ HTTP Client)
### List films (default pagination)
GET http://localhost:8080/films
Accept: application/hal+json
### List films with expand and filters
GET http://localhost:8080/films?limit=5&offset=0&expand=actors,language&language.name=English
Accept: application/hal+json
### List films filtered by category name
GET http://localhost:8080/films?limit=5&category.name=Action
Accept: application/hal+json
### Get a single film
GET http://localhost:8080/films/1?expand=actors,language,original_language
Accept: application/hal+json
### Create a film (server computes next film_id)
POST http://localhost:8080/films
Content-Type: application/json
Accept: application/hal+json
{
"title": "Sample Movie",
"description": "A test film created via HTTP client",
"release_year": "2025",
"language_id": 1,
"rental_duration": 3,
"rental_rate": 4.99,
"length": 120,
"replacement_cost": 19.99,
"rating": "PG",
"special_features": "Trailers,Deleted Scenes"
}
### Create a film with explicit film_id
POST http://localhost:8080/films
Content-Type: application/json
Accept: application/hal+json
{
"film_id": 10001,
"title": "Explicit ID Film",
"language_id": 1
}
### Replace film (PUT)
# Note: Replace the :id variable below to match an existing film id
PUT http://localhost:8080/films/{{film_id}}
Content-Type: application/json
Accept: application/hal+json
{
"title": "Updated Title (PUT)",
"description": "Full replacement payload",
"release_year": "2024",
"language_id": 1,
"original_language_id": 2,
"rental_duration": 5,
"rental_rate": 3.99,
"length": 95,
"replacement_cost": 14.99,
"rating": "PG-13",
"special_features": "Trailers,Behind the Scenes"
}
### Patch film (partial update)
PATCH http://localhost:8080/films/{{film_id}}
Content-Type: application/json
Accept: application/hal+json
{
"title": "Patched Title",
"rental_rate": 2.99
}
### Delete film
DELETE http://localhost:8080/films/{{film_id}}
### Related: list actors of a film
GET http://localhost:8080/films/{{film_id}}/actors
Accept: application/hal+json

View file

@ -0,0 +1,5 @@
{
"dev": {
"film_id": "10001"
}
}

View file

@ -7,6 +7,7 @@ package sqlc
import (
"context"
"database/sql"
)
const countFilms = `-- name: CountFilms :one
@ -156,3 +157,184 @@ func (q *Queries) ListFilms(ctx context.Context, arg ListFilmsParams) ([]Film, e
}
return items, nil
}
// Additional film CRUD methods (manually added to mirror sqlc patterns)
const nextFilmID = `-- name: NextFilmID :one
SELECT COALESCE(MAX(film_id), 0) + 1 FROM film
`
func (q *Queries) NextFilmID(ctx context.Context) (int64, error) {
row := q.db.QueryRowContext(ctx, nextFilmID)
var id int64
err := row.Scan(&id)
return id, err
}
const insertFilm = `-- name: InsertFilm :exec
INSERT INTO film (
film_id,
title,
description,
release_year,
language_id,
original_language_id,
rental_duration,
rental_rate,
length,
replacement_cost,
rating,
special_features,
last_update
) VALUES (
?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP
)
`
type InsertFilmParams struct {
FilmID int64 `json:"film_id"`
Title string `json:"title"`
Description interface{} `json:"description"`
ReleaseYear sql.NullString `json:"release_year"`
LanguageID int64 `json:"language_id"`
OriginalLanguageID sql.NullInt64 `json:"original_language_id"`
RentalDuration int64 `json:"rental_duration"`
RentalRate float64 `json:"rental_rate"`
Length sql.NullInt64 `json:"length"`
ReplacementCost float64 `json:"replacement_cost"`
Rating sql.NullString `json:"rating"`
SpecialFeatures sql.NullString `json:"special_features"`
}
func (q *Queries) InsertFilm(ctx context.Context, arg InsertFilmParams) error {
_, err := q.db.ExecContext(ctx, insertFilm,
arg.FilmID,
arg.Title,
arg.Description,
arg.ReleaseYear,
arg.LanguageID,
arg.OriginalLanguageID,
arg.RentalDuration,
arg.RentalRate,
arg.Length,
arg.ReplacementCost,
arg.Rating,
arg.SpecialFeatures,
)
return err
}
const updateFilmPut = `-- name: UpdateFilmPut :execrows
UPDATE film SET
title = ?,
description = ?,
release_year = ?,
language_id = ?,
original_language_id = ?,
rental_duration = ?,
rental_rate = ?,
length = ?,
replacement_cost = ?,
rating = ?,
special_features = ?
WHERE film_id = ?
`
type UpdateFilmPutParams struct {
Title string `json:"title"`
Description interface{} `json:"description"`
ReleaseYear sql.NullString `json:"release_year"`
LanguageID int64 `json:"language_id"`
OriginalLanguageID sql.NullInt64 `json:"original_language_id"`
RentalDuration int64 `json:"rental_duration"`
RentalRate float64 `json:"rental_rate"`
Length sql.NullInt64 `json:"length"`
ReplacementCost float64 `json:"replacement_cost"`
Rating sql.NullString `json:"rating"`
SpecialFeatures sql.NullString `json:"special_features"`
FilmID int64 `json:"film_id"`
}
func (q *Queries) UpdateFilmPut(ctx context.Context, arg UpdateFilmPutParams) (int64, error) {
result, err := q.db.ExecContext(ctx, updateFilmPut,
arg.Title,
arg.Description,
arg.ReleaseYear,
arg.LanguageID,
arg.OriginalLanguageID,
arg.RentalDuration,
arg.RentalRate,
arg.Length,
arg.ReplacementCost,
arg.Rating,
arg.SpecialFeatures,
arg.FilmID,
)
if err != nil {
return 0, err
}
return result.RowsAffected()
}
const patchFilm = `-- name: PatchFilm :execrows
UPDATE film SET
title = COALESCE(?1, title),
description = COALESCE(?2, description),
release_year = COALESCE(?3, release_year),
language_id = COALESCE(?4, language_id),
original_language_id = COALESCE(?5, original_language_id),
rental_duration = COALESCE(?6, rental_duration),
rental_rate = COALESCE(?7, rental_rate),
length = COALESCE(?8, length),
replacement_cost = COALESCE(?9, replacement_cost),
rating = COALESCE(?10, rating),
special_features = COALESCE(?11, special_features)
WHERE film_id = ?12
`
type PatchFilmParams struct {
Title sql.NullString `json:"title"`
Description interface{} `json:"description"`
ReleaseYear sql.NullString `json:"release_year"`
LanguageID sql.NullInt64 `json:"language_id"`
OriginalLanguageID sql.NullInt64 `json:"original_language_id"`
RentalDuration sql.NullInt64 `json:"rental_duration"`
RentalRate sql.NullFloat64 `json:"rental_rate"`
Length sql.NullInt64 `json:"length"`
ReplacementCost sql.NullFloat64 `json:"replacement_cost"`
Rating sql.NullString `json:"rating"`
SpecialFeatures sql.NullString `json:"special_features"`
FilmID int64 `json:"film_id"`
}
func (q *Queries) PatchFilm(ctx context.Context, arg PatchFilmParams) (int64, error) {
result, err := q.db.ExecContext(ctx, patchFilm,
arg.Title,
arg.Description,
arg.ReleaseYear,
arg.LanguageID,
arg.OriginalLanguageID,
arg.RentalDuration,
arg.RentalRate,
arg.Length,
arg.ReplacementCost,
arg.Rating,
arg.SpecialFeatures,
arg.FilmID,
)
if err != nil {
return 0, err
}
return result.RowsAffected()
}
const deleteFilm = `-- name: DeleteFilm :execrows
DELETE FROM film WHERE film_id = ?
`
func (q *Queries) DeleteFilm(ctx context.Context, filmID int64) (int64, error) {
result, err := q.db.ExecContext(ctx, deleteFilm, filmID)
if err != nil {
return 0, err
}
return result.RowsAffected()
}

View file

@ -42,4 +42,59 @@ SELECT a.actor_id, a.first_name, a.last_name, a.last_update
FROM actor a
JOIN film_actor fa ON fa.actor_id = a.actor_id
WHERE fa.film_id = ?
ORDER BY a.last_name ASC, a.first_name ASC;
ORDER BY a.last_name ASC, a.first_name ASC;
-- name: NextFilmID :one
SELECT COALESCE(MAX(film_id), 0) + 1 FROM film;
-- name: InsertFilm :exec
INSERT INTO film (
film_id,
title,
description,
release_year,
language_id,
original_language_id,
rental_duration,
rental_rate,
length,
replacement_cost,
rating,
special_features,
last_update
) VALUES (
?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP
);
-- name: UpdateFilmPut :execrows
UPDATE film SET
title = ?,
description = ?,
release_year = ?,
language_id = ?,
original_language_id = ?,
rental_duration = ?,
rental_rate = ?,
length = ?,
replacement_cost = ?,
rating = ?,
special_features = ?
WHERE film_id = ?;
-- name: PatchFilm :execrows
UPDATE film SET
title = COALESCE(?1, title),
description = COALESCE(?2, description),
release_year = COALESCE(?3, release_year),
language_id = COALESCE(?4, language_id),
original_language_id = COALESCE(?5, original_language_id),
rental_duration = COALESCE(?6, rental_duration),
rental_rate = COALESCE(?7, rental_rate),
length = COALESCE(?8, length),
replacement_cost = COALESCE(?9, replacement_cost),
rating = COALESCE(?10, rating),
special_features = COALESCE(?11, special_features)
WHERE film_id = ?12;
-- name: DeleteFilm :execrows
DELETE FROM film WHERE film_id = ?;