Query Filters
Every read, update, and delete operation accepts zero or more predicates that narrow down which records are affected. Predicates are generated per model and live in each model's package (for example user.Email.EQ(...)).
The available operators depend on the field's scalar type:
- Every scalar field exposes the comparison and set operators.
- String fields additionally expose the string-matching operators.
- Optional fields expose null checks via
IsNullandIsNotNull. - Array fields expose
Has,HasEvery, andHasSome.
The same predicate types are passed to FindUnique, FindFirst, FindMany, Update, UpdateMany, Delete, DeleteMany, and Count.
Use the following Prisma schema as reference:
enum UserRole {
ADMIN
STUDENT
TEACHER
}
model User {
id String @id @default(cuid())
email String @unique
phoneNum String?
loginCount Int
bio String?
role UserRole?
tags String[]
}EQ
Matches records where a field equals a value. On unique fields, EQ returns a UniquePredicate and can also be used as a cursor.
users, err := db.User.FindMany(user.Email.EQ("x@y.com")).Exec(ctx)SELECT * FROM "users" WHERE "email" = 'x@y.com';NEQ
Matches records where a field is not equal to a value.
users, err := db.User.FindMany(user.Bio.NEQ("spam")).Exec(ctx)SELECT * FROM "users" WHERE "bio" != 'spam';GT / GTE
Matches records where a field is greater than - or greater than or equal to - a value.
users, err := db.User.FindMany(user.LoginCount.GT(10)).Exec(ctx)
users, err := db.User.FindMany(user.LoginCount.GTE(10)).Exec(ctx)SELECT * FROM "users" WHERE "loginCount" > 10;
SELECT * FROM "users" WHERE "loginCount" >= 10;LT / LTE
Matches records where a field is less than - or less than or equal to - a value.
users, err := db.User.FindMany(user.LoginCount.LT(10)).Exec(ctx)
users, err := db.User.FindMany(user.LoginCount.LTE(10)).Exec(ctx)SELECT * FROM "users" WHERE "loginCount" < 10;
SELECT * FROM "users" WHERE "loginCount" <= 10;In / NotIn
Matches records where a field is (or is not) one of a list of values.
users, err := db.User.FindMany(
user.Role.In([]phi.UserRoleType{phi.UserRole_ADMIN, phi.UserRole_TEACHER}),
).Exec(ctx)
users, err := db.User.FindMany(user.Email.NotIn([]string{"a@b.com", "c@d.com"})).Exec(ctx)SELECT * FROM "users" WHERE "role" IN ('ADMIN', 'TEACHER');
SELECT * FROM "users" WHERE "email" NOT IN ('a@b.com', 'c@d.com');Between
Matches records where a field falls within an inclusive range.
users, err := db.User.FindMany(user.LoginCount.Between(5, 100)).Exec(ctx)SELECT * FROM "users" WHERE "loginCount" BETWEEN 5 AND 100;Contains
Matches string fields that contain the given substring. This maps to SQL's LIKE '%value%'.
users, err := db.User.FindMany(user.Bio.Contains("golang")).Exec(ctx)SELECT * FROM "users" WHERE "bio" LIKE '%golang%';HasPrefix / HasSuffix
Matches string fields that begin or end with a given substring.
users, err := db.User.FindMany(user.Email.HasPrefix("admin")).Exec(ctx)
users, err := db.User.FindMany(user.Email.HasSuffix("@example.com")).Exec(ctx)SELECT * FROM "users" WHERE "email" LIKE 'admin%';
SELECT * FROM "users" WHERE "email" LIKE '%@example.com';Like / ILike
Provides raw LIKE pattern matching. Use % as a wildcard. ILike performs a case-insensitive match on the underlying database.
users, err := db.User.FindMany(user.Email.Like("%@example.com")).Exec(ctx)
users, err := db.User.FindMany(user.Bio.ILike("%golang%")).Exec(ctx)SELECT * FROM "users" WHERE "email" LIKE '%@example.com';
-- Case-insensitive, e.g. uses "email" ILIKE '%golang%' on PostgreSQL
SELECT * FROM "users" WHERE "bio" ILIKE '%golang%';Note: Dialects vary. PostgreSQL supports a native
ILIKE, soILikemaps directly tocol ILIKE val. SQLite has noILIKEoperator, so Phi emulates it withLOWER(col) LIKE LOWER(val)to get the same case-insensitive behavior.
IsNull / IsNotNull
Match records where an optional field is null or not null.
users, err := db.User.FindMany(user.Bio.IsNull()).Exec(ctx)
users, err := db.User.FindMany(user.Bio.IsNotNull()).Exec(ctx)SELECT * FROM "users" WHERE "bio" IS NULL;
SELECT * FROM "users" WHERE "bio" IS NOT NULL;And
Combines predicates so that all of them must match; it compiles to the same AND in SQL.
users, err := db.User.FindMany(
user.And(
user.LoginCount.GTE(10),
user.Email.HasSuffix("@example.com"),
),
).Exec(ctx)SELECT * FROM "users" WHERE "loginCount" >= 10 AND "email" LIKE '%@example.com';Multiple Predicates Are AND-ed
Query methods accept zero or more predicates, so you can usually pass conditions directly without And. Every predicate passed to a method is combined with AND in the generated SQL:
users, err := db.User.FindMany(
user.LoginCount.GTE(10),
user.Email.HasSuffix("@example.com"),
).Exec(ctx)SELECT * FROM "users" WHERE "loginCount" >= 10 AND "email" LIKE '%@example.com';The two produce identical SQL. Choose based on what you are doing:
- Method arguments (
FindMany(p1, p2)) - the simplest, most readable way to flatten a set ofANDconditions. Use this for everyday filtering. user.And(p1, p2, ...)- bundles several predicates into a single value you can store, reuse, or pass as one argument. Use this when a condition needs to be shared across queries, built at runtime, passed into a helper, or embedded inside a larger boolean expression such asuser.Or(user.And(a, b), user.And(c, d)). Because it returns one predicate, you can nest it insideAnd,Or, orNot, which require individual predicate values.
Or
Combines predicates so that any one of them may match.
users, err := db.User.FindMany(
user.Or(
user.Role.EQ(phi.UserRole_ADMIN),
user.LoginCount.GTE(100),
),
).Exec(ctx)SELECT * FROM "users" WHERE "role" = 'ADMIN' OR "loginCount" >= 100;Not
Negates a single predicate.
users, err := db.User.FindMany(
user.Not(user.Role.EQ(phi.UserRole_ADMIN)),
).Exec(ctx)SELECT * FROM "users" WHERE NOT ("role" = 'ADMIN');Array Fields
Array fields (such as tags String[]) expose containment operators:
Has(value)- the array contains the value.HasEvery(values)- the array contains every value.HasSome(values)- the array contains at least one value.
users, err := db.User.FindMany(user.Tags.HasEvery([]string{"go", "grpc"})).Exec(ctx)Note: Predicates are compiled after validation. Any predicate that fails validation produces an error instead of running an invalid query.