On this page

Build a useful data layer

Add notes to the task and look up a task that may not exist. You will see the difference between a NULL column and a missing row.

Starting point

Continue in the practice application's 01_first_query directory after your first query.

Step 1: Add notes

Create db/migrations/0002_notes.up.sql:

ALTER TABLE tasks ADD COLUMN notes TEXT;

There is no NOT NULL constraint, so a task can have no note. Seagull represents this value as a string pointer.

Append these queries to db/queries/tasks.sql:

-- sgl.query(SetNotes, exec)
UPDATE tasks SET notes = ? WHERE id = ?;

-- sgl.query(FindTask, one, optional: true)
SELECT id, title, notes FROM tasks WHERE id = ?;

SetNotes has two inputs, so it receives a parameter struct. FindTask uses optional: true, so it returns a presence boolean along with the row and error.

../sgl generate

Step 2: Set and read a note

Append this code inside run, before its final return nil:

	if err := queries.SetNotes(ctx, store.SetNotesParams{Notes: new("Bring chips"), ID: task.ID}); err != nil {
		return err
	}
	found, ok, err := queries.FindTask(ctx, task.ID)
	if err != nil {
		return err
	}
	if !ok || found.Notes == nil {
		return fmt.Errorf("task or notes missing")
	}
	fmt.Fprintln(out, *found.Notes)
	_, ok, err = queries.FindTask(ctx, 999)
	if err != nil {
		return err
	}
	fmt.Fprintln(out, "missing:", !ok)

The first lookup checks that both the task and its note exist before reading the pointer. The second asks for ID 999, which this application has not created.

go run .
1 Feed the seagulls
Bring chips
missing: true

The note is present, while the second row is missing. A present task with NULL notes would instead have ok == true and found.Notes == nil.

Continue with search and results. See null and missing rows when choosing the contract for an application query.