Query builder for Dgraph database.
Table of contents
- Install
- Projection
- Operators
- Connecting Operators
- Filtering
- Pagination
- Directives
- Query Variables (refs)
- GraphQL Types
- Running a Query
- Demo
Install
Install using npm:
npm install @dgraphium/core
or yarn:
yarn add @dgraphium/core
Projection
Projection is basically an edge definition. Separately it can be
defined by: edge({...})
which is exported from @dgraphium/core
.
To define projection for a query:
query(...).project({ /* projection here */ })
For describing an edge, object is used. Object almost looks like the returned value.
Each key's value type in the projection object can be:
-
1 | true
: include field in a result.- if you pass
type
to containing edge/projection,key
maps to field:${capitalized type}.${key}
- if
type
is undefined, key maps to field with same name:${key}
- if you pass
-
0 | false
: don't include field in a result. -
string
: key will map to passed value. Key simply maps to it so the output will be:${key}: ${value}
-
Edge
: nested edge. -
Ref
: query/value reference.
Projection Merging
You can call query.project(...)
multiple times on same query object.
By default projections will deeply merge. New keys will be added, existing keys will be overwritten.
For example:
query.project({ a: 1, c: { d: 1 } });
query.project({ b: 1, c: { d: 0, k: 1 } });
/* resulting projection: {
a: 1,
b: 1 ,
c: { d: 0, k: 1 }
} */
You can do projection merging on Edge
as well using:
edge.merge({...})
.
To overwrite projection, you can set overwrite
to true
:
query.project({ a: 1 });
query.project({ b: 1 }, true);
// resulting projection: { b: 1 }
In case of Edge
: edge.merge({...}, true)
Operators
Operators/Functions can be imported from @dgraphium/core/operators
.
Supported operators:
basic operators
operator | description |
---|---|
type |
search by Type |
has |
find nodes which has field/edge/predicate |
uid |
find by uid |
predUid |
find by nested edge's uid |
simple comparison operators
operator | description |
---|---|
eq |
equals |
lt |
less than |
lte |
less than or equal to |
gt |
greater than |
gte |
greater than or equal to |
text operators
operator | description |
---|---|
regex |
regex search |
match |
fuzzy matching |
anyOfText |
full-text search with stemming and stop words to find strings matching any of the given text |
allOfText |
full-text search with stemming and stop words to find strings matching all of the given text |
anyOfTerms |
matches strings that have any of the specified terms in any order; case insensitive. |
allOfTerms |
matches strings that have all of the specified terms in any order; case insensitive. |
Connecting Operators
Note: connecting operators (LogicalOperators
) can't be used in query.func(...)
.
they can be imported by:
import { and, or, not } from '@dgraphium/core/operators';
Filtering
Operators can be used in filtering queries or nested edges.
-
filtering queries:
For example fetch users with age between 18 and 30:
query().filter(and(gt('age', 18), lt('age', 30)))
-
filtering nested edges: For example fetch user's posts, which has more than 10 likes:
query().projection({ posts: edge().filter(gt('likes', 10)), });
Pagination
All pagination methods are available for queries as well as nested edges.
-
.first(first: number)
: count of nodes to fetch (same as limit). -
.offset(offset: number)
: node offset or amount of nodes to skip. -
.after(id: Uid)
: fetch nodes after theid
.
you can also use
.withArgs(args: {
first: number,
offset: number,
after: Uid,
})
Directives
Query and Edge directives:
- cascade
Query only directives:
- ignoreReflex
Those directives are available on edge or query as a function, e.g.
edge.cascase()
.
Query Variables (refs)
Query variable (ref) can be created by calling ref(...path: string[])
method on query object. path
argument is a path to a field.
Note: unlike DQL, you can define as many refs as you want. Unless you use it somewhere, it will not be defined in the resulting query.
Query refs can be used either in projection (in which case field will
point to val(varName)
), or in func/filtering.
Path does not exist in query projection
New field will be added to varQuery projection and ref will point to it.
Examples
const varQuery = query().func(gt('age', 10));
const postsQuery = query()
.func(uid(varQuery.ref('posts')))
.project({ text: 1 });
postsQuery.toString()
outputs:
{
var(func: gt(age, 10)) {
posts: v1 as posts
}
q1(func: uid(v1)) {
text: text
}
}
Path exists in query projection
Ref will point to whatever is at the given path.
Examples
- pointed field with filtering:
const varQuery = query()
.func(gt('age', 10))
.project({
posts: edge().filter(regex('text', /mysql/))
});
const postsQuery = query()
.func(uid(varQuery.ref('posts')))
.project({ text: 1 });
postsQuery.toString()
outputs:
{
var(func: gt(age, 10)) {
posts: v1 as posts @filter(regexp(text, /mysql/)) {
}
}
q1(func: uid(v1)) {
text: text
}
}
- graphql type field:
const varQuery = query('user')
.func(gt('age', 10))
.project({
posts: edge('post').filter(regex('text', /mysql/)),
});
const postsQuery = query('post')
.func(uid(varQuery.ref('posts')))
.project({ text: 1 });
postsQuery.toString()
outputs:
{
var(func: gt(User.age, 10)) {
posts: v1 as User.posts @filter(regexp(Post.text, /mysql/)) {
}
}
q1(func: uid(v1)) {
text: Post.text
}
}
GraphQL Types
If you have GraphQL schema, when you deploy that schema to Dgraph database, each field gets prefixed by it's type.
for example:
type User {
id: ID!
name: String!
age: Int!
posts: [Post]
}
type Post {
id: ID!
text: String!
replyCount: Int
}
results in following Dgraph schema:
type User {
User.name
User.age
User.posts
}
type Post {
Post.text
Post.replyCount
}
User.name: string
User.age: int
User.posts: [uid]
so to query such data, you need to prefix each field with it's type:
{
me(func: uid(0x2)) {
id: uid
name: User.name
age: User.age
posts: User.posts @filter(gt(Post.replyCount, 2)) {
id: uid
text: Post.text
replyCount: Post.replyCount
}
}
}
to achieve exactly above written query with Dgraphium:
query('user') // <- type User
.name('me')
.func(uid('0x2'))
.project({
id: 1,
name: 1,
age: 1,
posts: edge('post', { // <- type Post
id: 1,
text: 1,
replyCount: 1,
})
.filter(gt('replyCount', 2)),
})
Combine Queries
you can combine queries with:
import { combine } from '@dgraphium/core';
const combinedQuery = combine(
query1,
query2,
...
);
Note:
- don't call
build
method on query before passing tocombine
function. - query names should be unique.
Running a Query
You can run query or group of queries with @dgraphium/client:
await dgraphClient.newTxn().query(meQuery); // params will be included
Note: you can name parameters by:
param.name(paramName)
. For example:params.string('myStrValue').name('myParamName')
. This is useful when you want to reuse query and override parameters:for example:
await dgraphClient.newTxn().queryWithVars( queryWithParam, { '$myParamName': 'myStrValueNew' } );
Demo
import { query, edge } from '@dgraphium/core';
import { uid, regex, gt, gte, lt, and, or } from '@dgraphium/core/operators';
const meQuery = query()
.name('me')
.func(uid('0x2', '0x3', '0x4'))
.filter(and(
or(
regex('name', /zura/i),
regex('name', /benashvili/i),
),
gte('age', 15),
lt('age', 25)
))
.project({
id: 1, // uid = id
name: 1,
age: 1,
posts: edge({
id: 1,
text: 1,
})
.filter(gt('createdDate', new Date('2020-01-01')))
.first(10),
})
.first(1)
.build();
meQuery.toString()
outputs (built query string):
{
me(func: uid(0x2, 0x3, 0x4), first: 1) @filter((regexp(name, /zura/i) OR regexp(name, /benashvili/i)) AND ge(age, 15) AND lt(age, 25)) {
id: uid
name: name
age: age
posts: posts (first: 10) @filter(gt(createdDate, 2020-01-01T00:00:00.000Z)) {
id: uid
text: text
}
}
}
run query with @dgraphium/client:
await dgraphClient.newTxn().query(meQuery);
use GraphQL Variables(params) in query
import { query, edge, params } from '@dgraphium/core';
import { uid, regex, gt, gte, lt, and, or } from '@dgraphium/core/operators';
const meQuery = query()
.name('me')
.func(uid(params.uids('0x2', '0x3', '0x4')))
.filter(and(
or(
regex('name', params.regex(/zura/i)),
regex('name', params.regex(/benashvili/i)),
),
gte('age', params.int(15)),
lt('age', params.int(25))
))
.project({
id: 1, // uid = id
name: 1,
age: 1,
posts: edge({
id: 1,
text: 1,
})
.filter(gt(
'createdDate',
params.date(new Date('2020-01-01'))
))
.first(10),
})
.first(1)
.build();
meQuery.toString()
outputs (built query string):
query q($p2: string, $p1: string, $p3: string, $p4: string, $p5: int, $p6: int) {
me(func: uid($p1), first: 1) @filter((regexp(name, $p3) OR regexp(name, $p4)) AND ge(age, $p5) AND lt(age, $p6)) {
id: uid
name: name
age: age
posts: posts (first: 10) @filter(gt(createdDate, $p2)) {
id: uid
text: text
}
}
}
run query with @dgraphium/client:
await dgraphClient.newTxn().query(meQuery); // params will be included