Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve Typings for query.execute #175

Open
jameslaneconkling opened this issue Sep 20, 2018 · 2 comments
Open

Improve Typings for query.execute #175

jameslaneconkling opened this issue Sep 20, 2018 · 2 comments

Comments

@jameslaneconkling
Copy link

jameslaneconkling commented Sep 20, 2018

It would be nice if functions like execute returned typed results. Some potential steps towards that could be:

  • make the HTTP.Body generic:
type SuccessBody<T> = {
    status: number;
    statusText: string;
    headers: Headers;
    url: string
    ok: true;
    body: T;
}
    
type ErrorBody = {
    status: number;
    statusText: string;
    headers: Headers;
    url: string
    ok: false;
    body: {
        message: string,
        code: string
    };
}
    
export type Body<T = any> = SuccessBody<T> | ErrorBody

By making Body a tagged union of success and error types, a type guard can properly narrow Body based on the ok key:

const handleResponse = (res: HTTP.Body<SomeResponseType>) => {
  if (!res.ok) {
    return console.error(res.body.message); // res.body is of type { message: string, code: string }
  }
  console.log(res.body); // res.body is SomeResponseType
};

With that in place, execute could look something like:

type RDFIRITerm = { type: 'uri', value: string }
type RDFLiteralTerm = { type: 'literal', value: string, 'xml:lang'?: string, datatype?: string }
type RDFBlankTerm = { type: 'bnode', value: string }
type RDFTerm = RDFIRITerm | RDFLiteralTerm | RDFBlankTerm

type SPARQLSelectResult<Variable extends string> = {
    head: {
        vars: Variable[]
        link: string[]
    }
    results: {
        bindings: Array<{ [V in Variable]: RDFTerm }>
    }
}

type SPARQLAskResult = {
    head: {},
    boolean: boolean
}

type SPARQLResult<Variable extends string> = SPARQLSelectResult<Variable> | SPARQLAskResult

function execute<Variable extends string = ''>(
    conn: Connection, database: string, query: string, accept?: HTTP.AcceptMimeType, params?: object
): Promise<HTTP.Body<SPARQLResult<Variable>>>;

and be used like

query.execute<"name" | "age">(
  conn,
  'myDB',
  'SELECT * WHERE { :personA :name ?name ; :age ?age }',
  'application/sparql-results+json'
)
  .then((res) => {
    if (!res.ok) {
      return console.error(res.body.message);
    }

    console.log(res.body.head) // res.body.head is of type {} | { vars: ("name" | "age")[], link: string[], }
  });

If this is of interest, I'd be happy to open a PR.

@jameslaneconkling
Copy link
Author

jameslaneconkling commented Sep 20, 2018

Actually, we could do better by overloading execute to better preserve the type of the response, either a SPARQL select query result or ask query result. E.g.

function execute(
    conn: Connection, database: string, query: string, accept?: HTTP.AcceptMimeType, params?: object
): Promise<HTTP.Body<SPARQLResult<''>>>;
function execute<QueryType extends 'Ask'>(
    conn: Connection, database: string, query: string, accept?: HTTP.AcceptMimeType, params?: object
): Promise<HTTP.Body<SPARQLAskResult>>;
function execute<QueryType extends 'Select', Variable extends string = ''>(
    conn: Connection, database: string, query: string, accept?: HTTP.AcceptMimeType, params?: object
): Promise<HTTP.Body<SPARQLSelectResult<Variable>>>;

and to use:

query.execute<'Select', 'name' | 'age'>(
  conn,
  'myDB',
  'SELECT * WHERE { :personA :name ?name ; :age ?age }',
  'application/sparql-results+json'
)
  .then((res) => {
    if (!res.ok) {
      return console.error(res.body.message);
    }

    res.body.results.bindings.map((result) => ( // result is of type { name: RDFTerm, age: RDFTerm }
      console.log(result.name, result.age)
    ));
  });

@jmrog
Copy link
Contributor

jmrog commented Aug 5, 2019

We're currently working on a 2.0 release of stardog.js, which may improve things here. If it doesn't, it's something that we can consider doing then. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants