Commit 7705e98b authored by Laurent Wouters's avatar Laurent Wouters
Browse files

[fix] Support warnings when loading entities

parent 16160e069632
......@@ -37,9 +37,44 @@ export interface Ontology {
}
/**
* A resolver of objects from entities
* Common interface for loadable objects
*/
export type ObjectResolver = (entity: RdfEntity, metaClass: MetaClass) => any;
export interface Loadable {
/**
* The warning for this object
*/
__warnings: { [property: string]: string };
/**
* The uri for this object
*/
uri: string;
/**
* The properties for this object
*/
[name: string]: any;
}
export interface Loader {
/**
* The selected languages
*/
readonly languages: Language[];
/**
* Resolves an object from an entity and its meta-class
* @param entity An entity
* @param metaClass The associated meta-class
*/
resolve(entity: RdfEntity, metaClass: MetaClass): Loadable;
/**
* Warns of an issue while loading
* @param entity The affected entity
* @param property The affected property
* @param message The message
*/
warn(entity: RdfEntity, property: string, message: string): void;
}
/**
* Represents the data about a property
......@@ -65,10 +100,9 @@ export interface MetaProperty {
/**
* Loads the value(s) of this property
* @param entity An entity
* @param languages The selected languages
* @param resolver The object resolver to use
* @param loader The loader
*/
load(entity: RdfEntity, languages: Language[], resolver: ObjectResolver): any;
load(entity: RdfEntity, loader: Loader): any;
}
/**
......@@ -122,14 +156,9 @@ export class MetaPropertyData implements MetaProperty {
/**
* Loads the value(s) of this property
* @param entity An entity
* @param languages The selected languages
* @param resolver The object resolver to use
* @param loader The loader
*/
public load(
entity: RdfEntity,
languages: Language[],
resolver: ObjectResolver
): any {
public load(entity: RdfEntity, loader: Loader): any {
let literals = entity.getValuesForS(this.uri);
literals = literals.filter((node: $rdf.Node) => node.termType == "Literal");
if (literals.length == 0) return this.isVector ? [] : null;
......@@ -137,10 +166,10 @@ export class MetaPropertyData implements MetaProperty {
let matching = literals
.map((literal: $rdf.Literal) => {
// is it tagged by one of the requested language?
for (var l = 0; l != languages.length; l++) {
for (var l = 0; l != loader.languages.length; l++) {
if (
literal.lang == languages[l].iso639_1 ||
literal.lang == languages[l].iso639_2
literal.lang == loader.languages[l].iso639_1 ||
literal.lang == loader.languages[l].iso639_2
)
// ok => it has the priority of the language
return { literal: literal, rank: l } as RankedLiteral;
......@@ -151,15 +180,25 @@ export class MetaPropertyData implements MetaProperty {
literal.lang == ""
)
// lang-tag is not defined, has more priority than other tagged literals that do not match (considered as a default)
return { literal: literal, rank: languages.length } as RankedLiteral;
return {
literal: literal,
rank: loader.languages.length
} as RankedLiteral;
// this is tagged literal that is not matched by one of the requested language
return {
literal: literal,
rank: languages.length + 1
rank: loader.languages.length + 1
} as RankedLiteral;
})
.sort((a: RankedLiteral, b: RankedLiteral) => a.rank - b.rank);
if (matching[0].rank >= loader.languages.length) {
loader.warn(
entity,
this.name,
"Could not find a value for the requested language(s)"
);
}
if (!this.isVector) return matching[0].literal.value;
return matching
......@@ -219,24 +258,19 @@ export class MetaPropertyObject implements MetaProperty {
/**
* Loads the value(s) of this property
* @param entity An entity
* @param languages The selected languages
* @param resolver The object resolver to use
* @param loader The loader
*/
public load(
entity: RdfEntity,
languages: Language[],
resolver: ObjectResolver
): any {
public load(entity: RdfEntity, loader: Loader): any {
let result: RdfEntity[] = [];
entity.getEntitiesForS(this.uri).forEach((e: RdfEntity) => {
if (result.indexOf(e) < 0) result.push(e);
});
result = result.map((e: RdfEntity) => {
let objects = result.map((e: RdfEntity) => {
let focus = e.getEntityForS("http://xmlns.com/foaf/0.1/focus");
let real = focus != null ? focus : e;
return resolver(real, this.metaClass);
return loader.resolve(real, this.metaClass);
});
return this.isVector ? result : result.length == 0 ? null : result[0];
return this.isVector ? objects : objects.length == 0 ? null : objects[0];
}
}
......@@ -252,18 +286,16 @@ export class MetaClass {
/**
* Loads an instance of this metaclass from the specified entity
* @param entity An entity
* @param languages The selected languages
* @param result The resulting object
* @param resolver The object resolver to use
* @param loader The loader
*/
public loadProperties(
entity: RdfEntity,
languages: Language[],
result: any,
resolver: ObjectResolver
result: Loadable,
loader: Loader
): void {
this.properties.forEach((property: MetaProperty) => {
result[property.name] = property.load(entity, languages, resolver);
result[property.name] = property.load(entity, loader);
});
}
}
......@@ -283,53 +315,68 @@ class Item {
/**
* The resulting object
*/
object: any;
object: Loadable;
}
/**
* The loader of entities
*/
class Loader {
constructor() {
class LoaderImpl implements Loader {
constructor(languages: Language[]) {
this.languages = languages;
this.items = [];
this.resolve = this.resolve.bind(this);
this.close = this.close.bind(this);
}
/**
* The selected languages
*/
public readonly languages: Language[];
/**
* The items
*/
items: Item[];
public items: Item[];
/**
* Resolves an object from an entity and its meta-class
* @param entity An entity
* @param metaClass The associated meta-class
*/
resolve(entity: RdfEntity, metaClass: MetaClass): any {
public resolve(entity: RdfEntity, metaClass: MetaClass): Loadable {
let found = this.items.find((item: Item) => item.entity === entity);
if (found == undefined) {
found = {
entity: entity,
metaClass: metaClass,
object: { uri: entity.uris[0] }
object: { __warnings: {}, uri: entity.uris[0] }
};
this.items.push(found);
}
return found.object;
}
/**
* Warns of an issue while loading
* @param entity The affected entity
* @param property The affected property
* @param message The message
*/
public warn(entity: RdfEntity, property: string, message: string): void {
let found = this.items.find((item: Item) => item.entity === entity);
if (found == undefined) return;
found.object.__warnings[property] = message;
}
/**
* Closes this loader
* @param languages The selected languages
*/
close(languages: Language[]): void {
public close(): void {
let i = 0;
while (i < this.items.length) {
this.items[i].metaClass.loadProperties(
this.items[i].entity,
languages,
this.items[i].object,
this.resolve
this
);
i++;
}
......@@ -342,7 +389,7 @@ class Loader {
* @param context The current rendering context
* @param target The current RDF entity to be rendered
*/
export function loadEntity<T>(
export function loadEntity<T extends Loadable>(
renderer: ViewRenderer,
context: RenderingContext,
ontology: Ontology,
......@@ -358,8 +405,8 @@ export function loadEntity<T>(
let focus = entity.getEntityForS("http://xmlns.com/foaf/0.1/focus");
if (focus != null) entity = focus;
let loader = new Loader();
let loader = new LoaderImpl(renderer.getLanguagesFor(context, target));
loader.resolve(entity, metaClass);
loader.close(renderer.getLanguagesFor(context, target));
return loader.items[0].object;
loader.close();
return loader.items[0].object as T;
}
......@@ -128,8 +128,7 @@ export const ONTOLOGY: rdfMeta.Ontology = {
/**
* The data for a person
*/
export interface Person {
uri: string;
export interface Person extends rdfMeta.Loadable {
title: string;
gender: string;
nickname: string;
......@@ -156,8 +155,7 @@ export interface Person {
/**
* The data for a book
*/
export interface Book {
uri: string;
export interface Book extends rdfMeta.Loadable {
authors: Person[];
title: string;
abstract: string;
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment