brillout / brillout/wildcard-api

New query language

Open
#60 0 comments 0 reactions 0 assignees View on GitHub
enhancement experimental vision
Dominant language
JavaScript
Stars
368
Forks
14
PR merge metrics
No merged PRs in 30d

Description

This would be a new project entirely independent but compatible with Wildcard.

This is ambitious and I'm not sure if/when I'll finish this.

In case you ask yourself why this is necessary in the context of Wildcard: it's basically for large scale applications that need to decouple the development of several frontends from the backend development. For most users, Wildcard alone is enough.

A preview:
~~~js
// Browser-side

// Note how we only depend on Wildcard here.
import { server } from '@wildcard-api/client';

// The query syntax is JSON-like.
const posts = await server.query({
_table: 'posts',
authorId: {
_table: 'users',
id: '*',
username: 'brillout',
},
title: '*',
content: '*',
});
assert(posts[0].title==='Introducing a new query language');
assert(posts[0].content.startsWith(
'When GraphQL was announced I was super excited but after the honeymoon'
));

// Similarly for upserting data
await server.query({
_table: 'posts',
authorId: 'brillout',
title: 'NQL + Wildcard = <3',
content: 'WIP',
});

// There is a field with '*' => data retrieval
// No field with '*' => data mutation
~~~

Resolvers + Wildcard integration

~~~js
const { server } = require('@wildcard-api/server');
const { resolveQuery, addResolver } = require('nql');

server.query = async function(query) {
const { data } = await resolveQuery(query);
return data;
};

// One resolver per table for data retrieval
addResolver('posts', async (selectFields, filterFields) => {
// A trick is that `filterFields[fieldName]` is always an array.
// This solves the N+1 problem!
assert(!filterFields.id || filterFields.id.constructor === Array);

// (No SQL injection, everything is sanitized.)
const res = await db.sql([
`SELECT ${selectFields.join(', ')} FROM posts`,
// Do this for every `key in filterFields`.
`WHERE id IN (`${filterFields.id.map(id => `'${id}'`).join(', ')})`,
].join(' '));

return res;
});

// One resolver per table is enough for any graph-like query.
// With no N+1 problem.
~~~

With "object-level permissions":

~~~js
const { server } = require('@wildcard-api/server');
const { resolveQuery, addPermissions } = require('nql');

server.query = async function(query) {
// We need the context for permissions
const context = this;
const { data, permissionDenied } = await resolveQuery(query, context);
if (permissionDenied) {
return { permissionDenied };
} else {
return { data };
}
};

// We define permissions programmatically.
// This is simple and powerful.
addPermissions('read', ({object, context}) => {
const { isAdmin } = context.user;
// Admins can read everything
if (isAdmin) {
return true;
}

// Anyone can read everything from the `posts` table
if (object._table==='posts') {
return true;
}

// Fine grained permission: anyone can read everything from
// the `users` table except for the `password` field.
if (object._table === 'users') {
if (object.password) {
return false;
} else {
return true;
}
}

// Anything else is forbidden
return false;
});

addPermissions('write', ({object, context}) => {
// Same than above but for mutation
});
~~~

Contributor guide

No contributing guide indexed for this repository

Research direction

The issue contains JavaScript previews for the proposed query syntax, resolver integration, and object-level permissions, but names no repository files, tests, or implementation entry points. Start by reviewing the existing Wildcard API structure and determine the project scope; the issue does not define a concrete completion criterion.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript, node.js
Domain
api, backend
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
15/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.