Query builder for Dgraph database.
- Install
- Projection
- Operators
- Connecting Operators
- Filtering
- Pagination
- Directives
- Query Variables (refs)
- GraphQL Types
- Running a Query
- Demo
Install using npm:
npm install @dgraphium/core
or yarn:
yarn add @dgraphium/core
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.
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/Functions can be imported from @dgraphium/core/operators
.
Supported 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 |
operator | description |
---|---|
eq |
equals |
lt |
less than |
lte |
less than or equal to |
gt |
greater than |
gte |
greater than or equal to |
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. |
Note: connecting operators (LogicalOperators
) can't be used in query.func(...)
.
they can be imported by:
import { and, or, not } from '@dgraphium/core/operators';
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)), });
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,
})
Query and Edge directives:
- cascade
Query only directives:
- ignoreReflex
- recurse
Those directives are available on edge or query as a function, e.g.
edge.cascase()
.
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.
New field will be added to varQuery projection and ref will point to it.
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
}
}
Ref will point to whatever is at the given path.
- 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
}
}
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)),
})
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.
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' } );
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);
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