Slide 42 de 53

Filtros opcionais: WHERE { }

type Colony {
	name:   Str
	apiary: Str
	frames: Int
}

query findColonies(apiary: Str, minFrames: Int, small: Bool, huge: Bool): Colony[dyn] {
	SELECT name, apiary, frames FROM colonies
	WHERE {
		if apiary != ""  { apiary = {apiary} }
		if minFrames > 0 { frames >= {minFrames} }
		or {
			if small { frames < 4 }
			if huge  { frames > 10 }
		}
	}
	ORDER BY name
}

proc main(): void {
	opened := hive.sql.pool(hive.sql.DatabaseDriver.SQLite(), "file::memory:?cache=shared", 1, 1)
	if opened is Result.Ok(db) {
		using db run raw "CREATE TABLE colonies (name TEXT, apiary TEXT, frames INTEGER)"
		using db run raw "INSERT INTO colonies VALUES ('north', 'orchard', 12)"
		using db run raw "INSERT INTO colonies VALUES ('south', 'orchard', 2)"
		using db run raw "INSERT INTO colonies VALUES ('east', 'meadow', 7)"

		// Tudo desligado: nenhum predicado vale, então não há WHERE algum.
		if using db run findColonies("", 0, false, false) is Result.Ok(all) {
			echo len(all)
		}
		// apiary AND frames >= 5 AND (frames > 10).
		if using db run findColonies("orchard", 5, false, true) is Result.Ok(some) {
			echo some
		}
		hive.sql.close(db)
	}
}
Uma tela de busca com quatro campos é quatro predicados opcionais, e montar isso como texto é de onde vêm tanto a injeção de SQL quanto o "WHERE 1 = 1". Um bloco WHERE é a declaração que substitui isso: ele junta com AND os predicados cujas condições valem, e um or { } ou and { } aninhado inverte o conectivo do grupo dentro dele.Um grupo que não contribui com nada desaparece em vez de deixar um conectivo solto, um grupo que contribui com mais de um predicado é parentetizado, e quando nenhum predicado vale, não existe cláusula WHERE alguma na instrução — então não há 1 = 1 para escrever nem para ler depois em um log. O texto de cada ramo é fixado em tempo de compilação; a única coisa decidida enquanto o programa roda é quais ramos são tomados. Os valores continuam viajando como parâmetros vinculados, exatamente como em uma query comum.Duas coisas que um bloco where deliberadamente não faz. Um nome de coluna ou uma direção de ordenação nunca pode ser um parâmetro — ORDER BY {col} ordenaria toda linha por uma string constante — então faça dessa escolha um tipo com variantes e despache para uma query por ordenação. E o SQL que você de fato monta na mão passa por run raw, que é sem tipo por construção e fácil de encontrar com grep.