#The function completes execution before the database has time to finish the update operation.

41 messages · Page 1 of 1 (latest)

low cedar
#

the code : ```go
func Learning(w http.ResponseWriter, r *http.Request) {
user := RetrieveUserFromContext(r)
learn := RetreiveLearningFromContext(r)
if learn == nil {
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}

wd, err := user.RetrieveLearningAndWord(r)
if err != nil {
    slog.Error("Erreur lors de la récupération de l'apprentissage", "détail", err)
    http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
    return
}

fmt.Printf("%#+v", learn)
switch {
case !learn.ProposeDejaVu && !learn.DejaVu:
    RenderTurbo(w, r, "dejavu", wd)
case !learn.View:
    RenderTurbo(w, r, "view", wd)
case !learn.Write:
    RenderTurbo(w, r, "write", wd)
case !learn.Composition:
    RenderTurbo(w, r, "compose", wd)
case !learn.Inverse:
    RenderTurbo(w, r, "inverse", wd)

default:
    http.Error(w, "État d'apprentissage inconnu", http.StatusInternalServerError)
}

}

#
func PostDejaVuHandler(w http.ResponseWriter, r *http.Request) {
    user := RetrieveUserFromContext(r)
    learn := RetreiveLearningFromContext(r)

    answer := r.FormValue("answer")

    correct, err := strconv.ParseBool(answer)
    if err != nil {
        http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
        return
    }

    if correct {
        if err := UpdateTrueOnDejaVu(r.Context(), learn.UserId); err != nil {
            slog.Error("Erreur lors de la mise à jour de DejaVu", "détail", err)
            http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
            return
        }
        if end, err := user.Next(r.Context()); err != nil {
            slog.Error("Erreur lors de la progression de l'apprentissage", "détail", err)
            http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
            return
        } else if end {
            fmt.Fprint(w, "Vous avez terminé le sujet.")
            return
        }
        return
    }
    if err := UpdateTrueOnProposeDejaVu(r.Context(), learn.UserId); err != nil {
        http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
        return
    }
    Learning(w, r)
}
gritty frost
#

can you please show how you interact with DB?

#

and how did you conclude function exits before DB does write?

low cedar
gritty frost
low cedar
#

this is how update function is writter : ```go
func UpdateTrueOnDejaVu(ctx context.Context, userId string) error {
query := UPDATE learning SET deja_vu = true WHERE user_id = $1
if _, err := dbconn.ExecContext(ctx, query, userId); err != nil {
return err
}
return nil
}

#
func (u *Users) RetrieveLearningAndWord(r *http.Request) (*Words, error) {
    ctx := r.Context()
    l, ok := ctx.Value(learningkey).(*learning)
    if !ok {
        err := errors.New("invalid type assertion for learning")
        slog.Error("RetrieveLearningAndWord: " + err.Error())
        return nil, err
    }

    wd, err := GetTextAndTranslation(ctx, l.TextId)
    if err != nil {
        slog.Error("RetrieveLearningAndWord: failed to get text and translations", "details", err.Error())
        return nil, err
    }

    return wd, nil
}
#
func GetTextAndTranslation(ctx context.Context, textId string) (*Words, error) {
    var w Words
    query := `SELECT id, text, translation FROM words WHERE id = $1`

    if err := dbconn.QueryRowContext(ctx, query, textId).Scan(&w.Id, &w.Text, &w.Translation); err != nil {
        return nil, err
    }
    return &w, nil
}
#
func GetNextWord(ctx context.Context, userId string) error {
    tx, err := dbconn.BeginTx(ctx, nil) // Start a transaction
    if err != nil {
        return err
    }
    defer tx.Rollback() // Rollback if anything fails

    // Step 1: Get current word
    var textId string
    err = tx.QueryRowContext(ctx, "SELECT text_id FROM learning WHERE user_id = $1", userId).Scan(&textId)
    if err != nil {
        if errors.Is(err, sql.ErrNoRows) {
            return fmt.Errorf("sql no rows: no current word found for user %s", userId)
        }
        return err
    }
    _, err = tx.ExecContext(ctx, "INSERT INTO history(user_id, text_id) VALUES($1, $2)", userId, textId)
    if err != nil {
        return err
    }

    var nextWordId string
    err = tx.QueryRowContext(ctx, `
SELECT id FROM words 
WHERE topic_id = (SELECT topic_id FROM words WHERE id = $1)
  AND sequence > (SELECT sequence FROM words WHERE id = $1)
ORDER BY sequence ASC 
LIMIT 1;
`, textId).Scan(&nextWordId)
    if err != nil {
        return err
    }

    _, err = tx.ExecContext(ctx, "DELETE FROM learning WHERE text_id = $1 AND user_id = $2", textId, userId)
    if err != nil {
        return err
    }

    _, err = tx.ExecContext(ctx, "INSERT INTO learning(text_id, user_id) VALUES($1, $2) ON CONFLICT DO NOTHING", nextWordId, userId)
    if err != nil {
        return err
    }

    return tx.Commit() 
}
#

fmt.Printf("%#+v", learn) before the switch statement

so for this when i send back to Learning(w,r) it take the learning that is pass through context because i use a middleware to call getlearning() since i need it a lot

gritty frost
#

can you please elaborate what means "I send back to Learning(w, r)"?

low cedar
#

func PostDejaVuHandler(w http.ResponseWriter, r *http.Request) {
user := RetrieveUserFromContext(r)
learn := RetreiveLearningFromContext(r)

answer := r.FormValue("answer")

correct, err := strconv.ParseBool(answer)
if err != nil {
    http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
    return
}

if correct {
    if err := UpdateTrueOnDejaVu(r.Context(), learn.UserId); err != nil {
        slog.Error("Erreur lors de la mise à jour de DejaVu", "détail", err)
        http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
        return
    }
    if end, err := user.Next(r.Context()); err != nil {
        slog.Error("Erreur lors de la progression de l'apprentissage", "détail", err)
        http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
        return
    } else if end {
        fmt.Fprint(w, "Vous avez terminé le sujet.")
        return
    }
    return
}
if err := UpdateTrueOnProposeDejaVu(r.Context(), learn.UserId); err != nil {
    http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
    return
}
Learning(w, r)

}

in each post i call again the Learning handler at the end. what it do ?
it like a loop; it call the learning state of the user,
if proposeDejaVu is false && DejaVu is false it send a template via hotwire turbo
if one of them it's true that mean i already ask the user this; if view is false i send another template (a differnt one from deja vu )
etc when user a full of true somewere i generate the next word it use to be in the PostHandler for the learn.Inverse case

gritty frost
#

and so your problem is that Learning does not get executed, right?

low cedar
# gritty frost and so your problem is that Learning does not get executed, right?

no is not that.
learning(w,r) is executed before the db has been update.

there is the scenario.
Let's say you are my user app.
when you end the sign up/ or login process.
i show you a word ans aske you if you know it already.
if you said yes; i show you another and so on; of course it update the db like this we all know you already know it;
if you said no i update proposeDejaVu so i know i've already ask you this question then send again trough Learning(w,r)

#

learning in the current state should now know that proposeDejavu is true

#

but learning.ProposeDejaVu is still false

#

so user have to click 2 time on subsmit so it can have to updated data because the first one not have the time to end the update

gritty frost
#

I see you're doing UPDATE there

#

if you have no rows, it won't add rows and update nothing

#

and all other functions (UpdateTrueOnDejaVu, ...) are not invoked if correct is set to false

#

maybe it's better to add more logging (temporary) to see how execution flow goes?

#

like, log pretty much every step

#

or just with print(...)

low cedar
#

maybe i would be better for both

#

can i ?

gritty frost
#

I think you can attach file to the message, yeah

worthy acorn
#

calling Learning(w, r) does exactly what it says, it will not call the middleware that you rely on to update your context value

low cedar
#

but i can understand because when i reload the second case fired

low cedar
gritty frost
#

It flipped to true in database

#

still don't get what's the problem

low cedar
gritty frost
buoyant scarab
#

I think I get what you mean, but what does RetreiveLearningFromContext() do?

worthy acorn
low cedar
low cedar