diff --git a/Avoiding-Code-Duplication-with-the-Select-Builder.md b/Avoiding-Code-Duplication-with-the-Select-Builder.md new file mode 100644 index 0000000..db9208b --- /dev/null +++ b/Avoiding-Code-Duplication-with-the-Select-Builder.md @@ -0,0 +1,59 @@ +## The Select Generator Feature + +There are good reasons not to use `SELECT *` queries the most important +of them is that you might end up loading more information than you are actually +going to use putting more pressure on your database for no good reason. + +To prevent that KSQL has a feature specifically for building the `SELECT` +part of the query using the tags from the input struct. +Using it is very simple and it works with all the 3 Query\* functions: + +Querying a single user: + +```golang +var user User +err = db.QueryOne(ctx, &user, "FROM users WHERE id = ?", userID) +if err != nil { + panic(err.Error()) +} +``` + +Querying a page of users: + +```golang +var users []User +err = db.Query(ctx, &users, "FROM users WHERE type = ? ORDER BY id LIMIT ? OFFSET ?", "Cristina", limit, offset) +if err != nil { + panic(err.Error()) +} +``` + +Querying all the users, or any potentially big number of users, from the database (not usual, but supported): + +```golang +err = db.QueryChunks(ctx, ksql.ChunkParser{ + Query: "FROM users WHERE type = ?", + Params: []interface{}{usersType}, + ChunkSize: 100, + ForEachChunk: func(users []User) error { + err := sendUsersSomewhere(users) + if err != nil { + // This will abort the QueryChunks loop and return this error + return err + } + return nil + }, +}) +if err != nil { + panic(err.Error()) +} +``` + +The implementation of this feature is actually simple internally: + +First, we check if the query starts with the word `FROM`, +if it does then we just get the KSQL tags from the struct and +then use it for building the `SELECT` statement. + +The `SELECT` statement is then cached so we don't have to build it again +the next time making this process very efficient.