diff --git a/README.md b/README.md index 296ea09..4b47f93 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ import * as ldkit from "https://deno.land/x/ldkit/mod.ts"; ### Create data schema and set up RDF source ```ts -import { type Context, createLens } from "ldkit"; +import { createLens, type Options } from "ldkit"; import { dbo, rdfs, xsd } from "ldkit/namespaces"; // Create a schema @@ -54,14 +54,14 @@ const PersonSchema = { }, } as const; -// Create a context for query engine -const context: Context = { +// Create options for query engine +const options: Options = { sources: ["https://dbpedia.org/sparql"], // SPARQL endpoint language: "en", // Preferred language }; -// Create a resource using the data schema and context above -const Persons = createLens(PersonSchema, context); +// Create a resource using the data schema and options above +const Persons = createLens(PersonSchema, options); ``` ### List all available data diff --git a/docs/about-ldkit/index.md b/docs/about-ldkit/index.md index 4f0a2df..aa568a8 100644 --- a/docs/about-ldkit/index.md +++ b/docs/about-ldkit/index.md @@ -9,12 +9,12 @@ LDkit lets you access, display and modify any RDF data, and it works in browser, The typical LDkit workflow to access Linked Data comprises of these protocols: -- You define a data source and other options through - [Context](./components/context). +- You define a data source and other settings through + [Options](./components/options). - You define a [Namespace](./components/namespaces) for the data to be retrieved, or use an existing one. - You define a data [Schema](./components/schema) with the help of namespaces. -- You create a data [Lens](./components/lens) and pass it the schema and context +- You create a data [Lens](./components/lens) and pass it the schema and options to query data. - Optionally, you can tweak the [Query Engine](./components/query-engine). diff --git a/docs/components/context.md b/docs/components/context.md deleted file mode 100644 index ee34eb4..0000000 --- a/docs/components/context.md +++ /dev/null @@ -1,57 +0,0 @@ -# Context - -Context is a configuration object that hosts LDkit settings for various of its -components. - -The only mandatory property of the context is to specify a RDF datasource. The -minimum example of such context is the following: - -```ts -import { type Context } from "ldkit"; - -const context: Context = { - sources: ["https://example.com/sparql"], -}; -``` - -The Context structure accepted by LDkit is derived from the -[RDF/JS Query specification](https://rdf.js.org/query-spec/) and made compatible -with Comunica context, for maximizing ease of adoption. Therefore, if you use -Comunica as a query engine with LDkit, chances are you do not have to to any -changes. - -## LDkit context properties - -| Key | Type | Description | -| ------------ | ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------- | -| **sources** | `string[]` or `IDataSource[]` | List of RDF sources. The default query engine included in LDkit accepts only a single source, and it must be a SPARQL endpoint. | -| **fetch** | `typeof fetch` | Custom fetch function. | -| **language** | `string` | Preferred data language - for cases when you query multilingual data. | -| **graph** | `string` | (**experimental**) IRI of a graph to constrain - if you want to query data stored in a particular named graph. | - -## Setting default context - -Context needs to be passed to a data [Lens](./lens) as a parameter, and there -are two ways how to handle that. Either you can pass the context directly as an -argument when creating the `Lens`, or you can set a context as a default one. If -there is a default context, then the `Lens` will use that context, if you do not -provide one directly. - -```ts -import { type Context, createLens, setDefaultContext } from "ldkit"; - -const context: Context = { - sources: ["https://example.com/sparql"], - language: "en", -}; - -setDefaultContext(context); - -const customContext: Context = { - ...context, - language: "cs", -}; - -const firstResource = createLens(FirstSchema); // will use the default context -const secondResource = createLens(SecondSchema, customContext); // will use custom context -``` diff --git a/docs/components/lens.md b/docs/components/lens.md index 41223b5..ff0c65f 100644 --- a/docs/components/lens.md +++ b/docs/components/lens.md @@ -8,20 +8,19 @@ data easily. In background, Lens handle building and executing SPARQL queries, data retrieval and transformation according to the data Schema. -## Creating a resource +## Creating a Lens instance -A Lens requires a [Schema](./schema), a [Context](./context), and a -[Query Engine](./query-engine). If you do not specify context or engine, default -ones will be used. +A Lens requires a [Schema](./schema) and an [Options](./options) object. You can +pass options either directly, or you can set up default global options. ```ts -import { type Context, createLens } from "ldkit"; +import { createLens, type Options } from "ldkit"; -const context: Context = { +const options = { sources: ["https://example.com/sparql"], -}; +} satisfies Options; -const MyLens = createLens(MySchema, context); // will use default query engine +const MyLens = createLens(MySchema, options); // will use default query engine ``` ## Lens usage @@ -32,12 +31,12 @@ of entities of type _dbo:Person_ that have a name, an abstract and a birth date. ### Create a Lens instance to query persons ```ts -import { type Context, createLens } from "ldkit"; +import { createLens, type Options } from "ldkit"; import { dbo, rdfs, xsd } from "ldkit/namespaces"; -const context: Context = { +const options = { sources: ["https://example.com/sparql"], -}; +} satisfies Options; // Create a schema const PersonSchema = { @@ -47,8 +46,8 @@ const PersonSchema = { birthDate: { "@id": dbo.birthDate, "@type": xsd.date }, } as const; -// Create a resource using the data schema and context above -const Persons = createLens(PersonSchema, context); +// Create a resource using the data schema and options object above +const Persons = createLens(PersonSchema, options); ``` ### List all matched persons diff --git a/docs/components/namespaces.md b/docs/components/namespaces.md index a2385ea..7f76373 100644 --- a/docs/components/namespaces.md +++ b/docs/components/namespaces.md @@ -45,7 +45,13 @@ console.log(schema.Person); // prints http://schema.org/Person > namespaces like this: > > ```ts -> import { rdf, schema } from "https://deno.land/x/ldkit@$VERSION/mod.ts"; +> import { rdf, schema } from "https://deno.land/x/ldkit@$VERSION/namespaces.ts"; +> ``` +> +> or directly like: +> +> ```ts +> import { rdf } from "https://deno.land/x/ldkit@$VERSION/namespaces/rdf.ts"; > ``` ### List of included namespaces @@ -57,6 +63,7 @@ console.log(schema.Person); // prints http://schema.org/Person | **dcterms** | DCMI Metadata Terms | http://purl.org/dc/terms/ | | **foaf** | FOAF ontology | http://xmlns.com/foaf/0.1/ | | **gr** | Good Relations | http://purl.org/goodrelations/v1# | +| **owl** | OWL Web Ontology Language | http://www.w3.org/2002/07/owl# | | **rdf** | RDF vocabulary | http://www.w3.org/1999/02/22-rdf-syntax-ns# | | **rdfs** | RDF Schema 1.1 | http://www.w3.org/2000/01/rdf-schema# | | **schema** | Schema.org | https://schema.org/ | diff --git a/docs/components/options.md b/docs/components/options.md new file mode 100644 index 0000000..ddb64ee --- /dev/null +++ b/docs/components/options.md @@ -0,0 +1,60 @@ +# Options + +_Options_ is a configuration object that hosts LDkit settings for various of its +components. + +The only mandatory property of the options is to specify one or more RDF +datasources. The minimum example of such context is the following: + +```ts +import { type Options } from "ldkit"; + +const options = { + sources: ["https://example.com/sparql"], +} satisfies Options; +``` + +The _Options_ structure accepted by LDkit is a superset of query engine +_Context_ defined in +[RDF/JS Query specification](https://rdf.js.org/query-spec/) and made compatible +with Comunica _Context_, for maximizing ease of adoption. Therefore, if you use +Comunica as a query engine with LDkit, chances are you do not have to to any +changes - just pass the Comunica context as LDkit options. + +## LDkit Options properties + +| Key | Type | Description | +| ------------ | ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------- | +| **engine** | `IQueryEngine` | Query engine to process SPARQL queries. LDkit uses the default query engine, unless specified otherwise. | +| **sources** | `string[]` or `IDataSource[]` | List of RDF sources. The default query engine included in LDkit accepts only a single source, and it must be a SPARQL endpoint. | +| **fetch** | `typeof fetch` | Custom fetch function. | +| **language** | `string` | Preferred data language - for cases when you query multilingual data. | +| **take** | `number` | Number of resources to return by default by the Lens object. The `LIMIT` property of a `SELECT` query. | +| **logQuery** | `(query: string) => void` | Function that is called every time a query is processed by the query engine. Useful for logging purposes. | + +## Setting default Options + +Options object needs to be passed to a data [Lens](./lens) as a parameter, and +there are two ways how to handle that. Either you can pass the object directly +as an argument when creating the `Lens` instance, or you can set a global +options. If there are global options set up, then the `Lens` will use the global +options object, unless you provide one directly when creating the instance. + +```ts +import { createLens, type Options, setGlobalOptions } from "ldkit"; + +const options = { + sources: ["https://example.com/sparql"], + language: "en", +} satisfies Options; + +setGlobalOptions(options); + +const customOptions = { + ...options, + language: "cs", +} satisfies Options; + +const firstResource = createLens(FirstSchema); // will use the global options +const secondResource = createLens(SecondSchema, customOptions); // will use custom options +``` diff --git a/docs/components/query-engine.md b/docs/components/query-engine.md index c7647d3..bf513e7 100644 --- a/docs/components/query-engine.md +++ b/docs/components/query-engine.md @@ -20,15 +20,15 @@ The `QueryEngine` follows [RDF/JS Query specification](https://rdf.js.org/query-spec/) and implements the `StringSparqlQueryable` interface. -The `QueryEngine` is configurable through [context](./context). +The `QueryEngine` is configurable through [Options](./options) object. ```ts -import { type Context, QueryEngine } from "ldkit"; +import { type Options, QueryEngine } from "ldkit"; -const context: Context = { +const options = { sources: ["https://example.com/sparql"], // required, must include one SPARQL endpoint fetch: customFetchFunction, // optional, must follow standard fetch interface -}; +} satisfies Options; const engine = new QueryEngine(); const response = await engine.queryBoolean("ASK { ?s ?p ?o }", context); @@ -37,7 +37,7 @@ const response = await engine.queryBoolean("ASK { ?s ?p ?o }", context); > Note: The default query engine supports all SPARQL endpoints that conform to > the SPARQL 1.1 specification and can return data of MIME > `application/sparql-results+json` for `SELECT` and `ASK` queries, and -> `application/rdf+json` for `CONSTRUCT` queries. +> `text/turtle` or `application/rdf+json` for `CONSTRUCT` queries. ## Custom query engine @@ -53,16 +53,16 @@ Comunica, or a custom engine derived from that - see A query engine instance needs to be passed to a data [Lens](./lens) as a parameter in order to query data, and there are two ways how to handle that. -Either you can pass the engine directly as an argument when creating the `Lens`, -or you can set an engine instance as a default one. If there is a default engine -instance, then the `Lens` will use that engine, if you do not provide one -directly. +Either you can pass the engine directly as part of options argument when +creating the `Lens` instance, or you can set an engine instance as a default +one. If there is a default engine instance, then the `Lens` will use that +engine, if you do not provide one directly. ```ts -import { createLens, setDefaultEngine } from "ldkit"; +import { createLens, setGlobalOptions } from "ldkit"; const engine = new MyCustomQueryEngine(); -setDefaultEngine(engine); +setGlobalOptions({ engine }); const MyLens = createLens(MySchema); // will use the custom engine, which is now default ``` diff --git a/docs/components/schema.md b/docs/components/schema.md index 1b88c56..30d35c9 100644 --- a/docs/components/schema.md +++ b/docs/components/schema.md @@ -42,7 +42,6 @@ following type: ```ts type PersonType = { $id: string; // IRI - $type: string[]; // defined in `@type` name: string; birthDate: Date; }; @@ -61,7 +60,8 @@ When defining a schema, you can specify: ### Entity type -Each schema must have at least one entity type defined. +You can define one or more entity RDF type to narrow the search results. Setting +the RDF type is recommended for optimal performance. ```ts const MySchema = { @@ -89,12 +89,13 @@ const MySchema = { "@optional": true, // if present, the property is optional "@array": true, // if present, the resulting property is always an array "@multilang": true, // if present, the resulting property is a map of languages and literals + "@schema": SomeSubschema, // if present, uses a nested schema }, } as const; ``` Unless specified otherwise, it is assumed that any property is of type -`xsd:string`, required, and not an array. You can override these default +`xsd:string`, required, and not an array. You can override these defaults per-property. In addition, there is a shortcut to specify default properties. The following @@ -139,7 +140,6 @@ const schema = { const convertedData = { $id: x.A, - $type: [x.Item], multilangProperty: { cs: "CS", en: "EN", @@ -160,6 +160,35 @@ const MySchema = { }; ``` +### Explicitly infer resulting TypeScript type of entities + +If you need, to explicitly use the resulting type of entities, that is, the +corresponding native TypeScript type of RDF data converted to JavaScript, you +can use the `SchemaInterface` helper type. + +```ts +import { type SchemaInterface } from "ldkit"; +import { dbo, rdfs, xsd } from "ldkit/namespaces"; + +const PersonSchema = { + "@type": dbo.Person, + name: rdfs.label, + birthDate: { + "@id": dbo.birthDate, + "@type": xsd.date, + }, +} as const; + +type PersonType = SchemaInterface; +/** + * { + * $id: IRI, // string alias + * name: string, + * birthDate: Date + * } + */ +``` + ## Complete schema reference The following schema showcases all possible supported variations. @@ -212,7 +241,6 @@ And the resulting type will be: ```ts type ThingType = { $id: string; - $type: string[]; required: string; optional: string | undefined; array: string[]; @@ -223,7 +251,6 @@ type ThingType = { date: Date; nested: { $id: string; - $type: string[]; nestedValue: string; }; }; diff --git a/docs/v2/filtering.md b/docs/features/filtering.md similarity index 100% rename from docs/v2/filtering.md rename to docs/features/filtering.md diff --git a/docs/how-to/index.md b/docs/features/index.md similarity index 100% rename from docs/how-to/index.md rename to docs/features/index.md diff --git a/docs/v2/inverse-properties.md b/docs/features/inverse-properties.md similarity index 100% rename from docs/v2/inverse-properties.md rename to docs/features/inverse-properties.md diff --git a/docs/v2/pagination.md b/docs/features/pagination.md similarity index 100% rename from docs/v2/pagination.md rename to docs/features/pagination.md diff --git a/docs/how-to/query-with-comunica.md b/docs/features/query-with-comunica.md similarity index 59% rename from docs/how-to/query-with-comunica.md rename to docs/features/query-with-comunica.md index 91ed22c..e9705f2 100644 --- a/docs/how-to/query-with-comunica.md +++ b/docs/features/query-with-comunica.md @@ -7,37 +7,37 @@ Comunica lets you access RDF data from multiple sources and various source types, including Solid pods, RDF files, Triple/Quad Pattern Fragments, HDT files. -> Note: If you need to access data through a SPARQL endpoint, it is recommended -> to use the default [Query Engine](../components/query-engine) shipped with -> LDkit. The built-in engine is lightweight and optimized for being used in -> browser. +> Note: If you need to access data through a single SPARQL endpoint, it is +> recommended to use the default [Query Engine](../components/query-engine) +> shipped with LDkit. The built-in engine is lightweight and optimized for being +> used in browser. To use Comunica with LDkit, simply pass its instance to a -[Lens](../components/lens), or set it as the default engine. The example below -shows a setup how to query in-memory data using +[Lens](../components/lens), or set it as the default engine using global +options. The example below shows a setup how to query in-memory data using [N3](https://github.com/rdfjs/N3.js/) store. This particular example uses the `@comunica/query-sparql-rdfjs` engine. ```ts -import { type Context, createLens } from "ldkit"; +import { createLens, type Options } from "ldkit"; import { QueryEngine as Comunica } from "@comunica/query-sparql-rdfjs"; import { Store } from "n3"; const store = new Store(); +const engine = new Comunica(); -const context: Context = { +const options = { sources: [store], -}; - -const engine = new Comunica(); + engine, +} satisfies Options; -const resource = createLens(MySchema, context, engine); +const resource = createLens(MySchema, options); ``` -The [context](../components/context) format for LDkit is the same as for -Comunica. The context that you pass to a resource, or a -[default context](../components/context) (if you set it up) eventually gets -passed to Comunica engine instance. +The [Options](../components/options) object schema for LDkit is the superset of +the _Context_ for Comunica. The _Options_ that you pass to a resource, or a +[default options](../components/options) object (if you set it up) eventually +gets passed to Comunica engine instance. ## Using Comunica as a server diff --git a/docs/features/supported-data-types.md b/docs/features/supported-data-types.md new file mode 100644 index 0000000..9614004 --- /dev/null +++ b/docs/features/supported-data-types.md @@ -0,0 +1,52 @@ +# Supported data types + +LDkit supports seamless two-way conversion between RDF based data types and +JavaScript / TypeScript native types. Both data and TypeScript types are +adequately converted. + +Each property in LDkit [Schema](../components/schema) can be assigned a +particular type. If it is not defined, then it defaults to `xsd:string`. + +In addition to regular RDF types, there is one special type `ldkit:IRI` that is +converted to a TypeScript type of `IRI`, which is an alias for string and it +represents and IRI (a value of `NamedNode`). + +| RDF Type | TypeScript type | +| ---------------------- | --------------- | +| xsd:dateTime | Date | +| xsd:date | Date | +| xsd:gDay | Date | +| xsd:gMonthDay | Date | +| xsd:gYear | Date | +| xsd:gYearMonth | Date | +| xsd:boolean | boolean | +| xsd:double | number | +| xsd:decimal | number | +| xsd:float | number | +| xsd:integer | number | +| xsd:long | number | +| xsd:int | number | +| xsd:byte | number | +| xsd:short | number | +| xsd:negativeInteger | number | +| xsd:nonNegativeInteger | number | +| xsd:nonPositiveInteger | number | +| xsd:positiveInteger | number | +| xsd:unsignedByte | number | +| xsd:unsignedInt | number | +| xsd:unsignedLong | number | +| xsd:unsignedShort | number | +| xsd:string | string | +| xsd:normalizedString | string | +| xsd:anyURI | string | +| xsd:base64Binary | string | +| xsd:language | string | +| xsd:Name | string | +| xsd:NCName | string | +| xsd:NMTOKEN | string | +| xsd:token | string | +| xsd:hexBinary | string | +| rdf:langString | string | +| xsd:time | string | +| xsd:duration | string | +| ldkit:IRI | IRI | diff --git a/docs/v2/working-with-arrays.md b/docs/features/working-with-arrays.md similarity index 100% rename from docs/v2/working-with-arrays.md rename to docs/features/working-with-arrays.md diff --git a/docs/getting-started/index.md b/docs/getting-started/index.md index 4c5dbe4..5b8b76a 100644 --- a/docs/getting-started/index.md +++ b/docs/getting-started/index.md @@ -16,7 +16,7 @@ import * as ldkit from "https://deno.land/x/ldkit/mod.ts"; ### Create data schema and set up RDF source ```ts -import { type Context, createLens } from "ldkit"; +import { createLens, type Options } from "ldkit"; import { dbo, rdfs, xsd } from "ldkit/namespaces"; // Create a schema @@ -30,14 +30,14 @@ const PersonSchema = { }, } as const; -// Create a context for query engine -const context: Context = { +// Create a options for query engine +const options = { sources: ["https://dbpedia.org/sparql"], // SPARQL endpoint language: "en", // Preferred language -}; +} satisfies Options; -// Create a resource using the data schema and context above -const Persons = createLens(PersonSchema, context); +// Create a resource using the data schema and options object above +const Persons = createLens(PersonSchema, options); ``` ### List all available data diff --git a/docs/table-of-contents.json b/docs/table-of-contents.json index 5469051..3607dae 100644 --- a/docs/table-of-contents.json +++ b/docs/table-of-contents.json @@ -10,23 +10,21 @@ "pages": [ ["schema", "Schema"], ["lens", "Lens"], - ["context", "Context"], + ["options", "Options"], ["namespaces", "Namespaces"], ["query-engine", "Query Engine"], ["power-tools", "Power Tools"] ] }, - "how-to": { - "title": "How To", - "pages": [["query-with-comunica", "Query with Comunica"]] - }, - "v2": { - "title": "Version 2 (not yet released)", + "features": { + "title": "Features", "pages": [ + ["query-with-comunica", "Query with Comunica"], ["filtering", "Filtering"], ["pagination", "Pagination"], ["working-with-arrays", "Working with arrays"], - ["inverse-properties", "Inverse properties"] + ["inverse-properties", "Inverse properties"], + ["supported-data-types", "Supported data types"] ] } } diff --git a/docs/v2/index.md b/docs/v2/index.md deleted file mode 100644 index 9fc34fc..0000000 --- a/docs/v2/index.md +++ /dev/null @@ -1,4 +0,0 @@ -# Version 2 (not yet released) - -This section of documentation describes upcoming features of LDkit that has not -yet been released. You can try them by checking out the GitHub repository. diff --git a/www/routes/index.tsx b/www/routes/index.tsx index 13c4b41..33faec0 100644 --- a/www/routes/index.tsx +++ b/www/routes/index.tsx @@ -41,13 +41,13 @@ export default function Home() { } const step1Markdown = ` -import { type Context, setDefaultContext } from "ldkit"; +import { type Options, setGlobalOptions } from "ldkit"; -const context: Context = { +const options = { sources: ["https://dbpedia.org/sparql"], -}; +} satisfies Options; -setDefaultContext(context); +setGlobalOptions(options); `; const step2Markdown = `