Skip to content

Commit

Permalink
Support for usages
Browse files Browse the repository at this point in the history
  • Loading branch information
sstenchlak committed Oct 25, 2023
1 parent 77212f0 commit 611da10
Show file tree
Hide file tree
Showing 14 changed files with 341 additions and 26 deletions.
50 changes: 50 additions & 0 deletions packages/core-v2/examples.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,4 +122,54 @@ local.executeOperation(createRelationship({
// Obtain final entities without any additional metadata
const entities = Object.values(aggregatorView.getEntities()).map(aggregated => aggregated.aggregatedEntity);
console.log(await generate(entities));
```

# UC04
```ts
import {SemanticModelAggregator} from "@dataspecer/core-v2/semantic-model/aggregator";
import {InMemorySemanticModel} from "@dataspecer/core-v2/semantic-model/in-memory";
import {createClass, createRelationship} from "@dataspecer/core-v2/semantic-model/operations"; // or replace nodejs with browser
import {createRelationshipUsage} from "@dataspecer/core-v2/semantic-model/usage/operations";

const aggregator = new SemanticModelAggregator();
const view = aggregator.getView();

const first = new InMemorySemanticModel();
aggregator.addModel(first);

const second = new InMemorySemanticModel();
aggregator.addModel(second);

// Create original entity
first.executeOperation(createRelationship({
id: "http://purl.org/dc/terms/title",
iri: "http://purl.org/dc/terms/title",
name: {en: "title"},
ends: [
{
concept: "http://www.w3.org/2002/07/owl#Thing"
},
{
concept: "http://www.w3.org/2002/07/owl#Thing"
}
]
}));

// Create dataset and usage of title
const datasetId = second.executeOperation(createClass({
name: {cs: "Dataset"},
})).id

second.executeOperation(createRelationshipUsage({
usageOf: "http://purl.org/dc/terms/title",
name: {cs: "Titulek datasetu"},
ends: [{
concept: datasetId
},{

}]
}));


console.log(view.getEntities());
```
4 changes: 3 additions & 1 deletion packages/core-v2/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@
"./semantic-model/simplified": "./lib/src/semantic-model/simplified/index.js",
"./semantic-model/lightweight-owl": "./lib/src/semantic-model/lightweight-owl/index.js",
"./semantic-model/operations": "./lib/src/semantic-model/operations/index.js",
"./semantic-model/in-memory": "./lib/src/semantic-model/in-memory/index.js"
"./semantic-model/in-memory": "./lib/src/semantic-model/in-memory/index.js",
"./semantic-model/usage/concepts": "./lib/src/semantic-model/usage/concepts/index.js",
"./semantic-model/usage/operations": "./lib/src/semantic-model/usage/operations/index.js"
},
"dependencies": {
"@dataspecer/core": "*",
Expand Down
1 change: 1 addition & 0 deletions packages/core-v2/src/project/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Project management
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/**
* Represents data specification project type
*/
export interface DataSpecification {

}
17 changes: 17 additions & 0 deletions packages/core-v2/src/semantic-model/concepts/concepts-utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import {Entity} from "../../entity-model";
import {SemanticModelClass, SemanticModelGeneralization, SemanticModelRelationship} from "./concepts";

export const SEMANTIC_MODEL_CLASS = "class"; // todo use proper IRI
export function isSemanticModelClass(resource: Entity | null): resource is SemanticModelClass {
return resource?.type.includes(SEMANTIC_MODEL_CLASS) ?? false;
}

export const SEMANTIC_MODEL_RELATIONSHIP = "relationship"; // todo use proper IRI
export function isSemanticModelRelationship(resource: Entity | null): resource is SemanticModelRelationship {
return resource?.type.includes(SEMANTIC_MODEL_RELATIONSHIP) ?? false;
}

export const SEMANTIC_MODEL_GENERALIZATION = "generalization"; // todo use proper IRI
export function isSemanticModelGeneralization(resource: Entity | null): resource is SemanticModelGeneralization {
return resource?.type.includes(SEMANTIC_MODEL_GENERALIZATION) ?? false;
}
20 changes: 3 additions & 17 deletions packages/core-v2/src/semantic-model/concepts/concepts.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {Entity} from "../../entity-model/entity";
import {SEMANTIC_MODEL_CLASS, SEMANTIC_MODEL_GENERALIZATION, SEMANTIC_MODEL_RELATIONSHIP} from "./concepts-utils";

/**
* A human text that is translated into multiple languages.
Expand All @@ -12,6 +13,8 @@ export interface SemanticModelEntity extends Entity {
* Public, usually globally-recognised, identifier of the entity.
* The value may be null indicating that the entity has no public IRI.
* @example http://xmlns.com/foaf/0.1/Person
*
* IRI may be relative to the base IRI of the model.
*/
iri: string | null;
}
Expand All @@ -31,12 +34,6 @@ export interface SemanticModelClass extends NamedThing, SemanticModelEntity {
// todo: is it class, enumeration, datatype, code list, ...
}

export const SEMANTIC_MODEL_CLASS = "class"; // todo use proper IRI

export function isSemanticModelClass(resource: Entity | null): resource is SemanticModelClass {
return resource?.type.includes(SEMANTIC_MODEL_CLASS) ?? false;
}

/**
* Represents attributes and associations.
*/
Expand All @@ -55,12 +52,6 @@ export interface SemanticModelRelationshipEnd extends NamedThing {
concept: string;
}

export const SEMANTIC_MODEL_RELATIONSHIP = "relationship"; // todo use proper IRI

export function isSemanticModelRelationship(resource: Entity | null): resource is SemanticModelRelationship {
return resource?.type.includes(SEMANTIC_MODEL_RELATIONSHIP) ?? false;
}

/**
* Inheritance hierarchy.
*/
Expand All @@ -74,8 +65,3 @@ export interface SemanticModelGeneralization extends SemanticModelEntity {
parent: string;
}

export const SEMANTIC_MODEL_GENERALIZATION = "generalization"; // todo use proper IRI

export function isSemanticModelGeneralization(resource: Entity | null): resource is SemanticModelGeneralization {
return resource?.type.includes(SEMANTIC_MODEL_GENERALIZATION) ?? false;
}
7 changes: 2 additions & 5 deletions packages/core-v2/src/semantic-model/concepts/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,2 @@
export {
SemanticModelClass, isSemanticModelClass,
SemanticModelGeneralization, isSemanticModelGeneralization,
SemanticModelRelationship, isSemanticModelRelationship
} from "./concepts";
export * from "./concepts";
export * from "./concepts-utils";
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@ import {
Operation
} from "../operations/operations";
import {SemanticModelClass, SemanticModelGeneralization, SemanticModelRelationship} from "../concepts/concepts";
import {
isCreateClassUsageOperation,
isCreateRelationshipUsageOperation,
isModifyClassUsageOperation, isModifyRelationshipUsageOperation
} from "../usage/operations";
import {SemanticModelClassUsage, SemanticModelRelationshipUsage} from "../usage/concepts";

function uuid() {
return Math.random().toString(36).substring(2) + Date.now().toString(36);
Expand Down Expand Up @@ -184,6 +190,123 @@ export class InMemorySemanticModel extends InMemoryEntityModel {
};
}

if (isCreateClassUsageOperation(operation)) {
let id = operation.entity.id;

// Generate random id if not provided
if (id === undefined) {
id = uuid();
}

if (this.entities[id]) {
return {
success: false,
};
}

const cls: SemanticModelClassUsage = {
id,
usageOf: operation.entity.usageOf,
type: ["class-usage"],
name: operation.entity.name ?? null,
description: operation.entity.description ?? null,
usageNote: operation.entity.usageNote ?? null,
};

this.change({[id]: cls}, []);
return {
success: true,
id,
} satisfies CreatedEntityOperationResult;
}

if (isModifyClassUsageOperation(operation)) {
if (!this.entities[operation.id]) {
return {
success: false,
};
}
this.change({[operation.id]: {...this.entities[operation.id]!, ...operation.entity}}, []);
return {
success: true,
};
}

if (isCreateRelationshipUsageOperation(operation)) {
let id = operation.entity.id;

// Generate random id if not provided
if (id === undefined) {
id = uuid();
}

if (this.entities[id]) {
return {
success: false,
};
}

const relationship: SemanticModelRelationshipUsage = {
usageNote: operation.entity.usageNote ?? null,
id,
type: ["relationship-usage"],
usageOf: operation.entity.usageOf,
name: operation.entity.name ?? null,
description: operation.entity.description ?? null,
ends: [
{
name: operation.entity.ends?.[0]?.name ?? null,
description: operation.entity.ends?.[0]?.description ?? null,
cardinality: operation.entity.ends?.[0]?.cardinality ?? null,
concept: operation.entity.ends?.[0]?.concept ?? null,
usageNote: operation.entity.ends?.[0]?.usageNote ?? null,
},
{
name: operation.entity.ends?.[1]?.name ?? null,
description: operation.entity.ends?.[1]?.description ?? null,
cardinality: operation.entity.ends?.[1]?.cardinality ?? null,
concept: operation.entity.ends?.[1]?.concept ?? null,
usageNote: operation.entity.ends?.[1]?.usageNote ?? null,
}
]
};

this.change({[id]: relationship}, []);
return {
success: true,
id,
} satisfies CreatedEntityOperationResult;
}

if (isModifyRelationshipUsageOperation(operation)) {
const oldRelationship = this.entities[operation.id] as SemanticModelRelationshipUsage | undefined

if (!oldRelationship) {
return {
success: false,
};
}

const updatedRelationship = {
...oldRelationship,
ends: [
{
...oldRelationship.ends[0],
...operation.entity.ends?.[0],
},
{
...oldRelationship.ends[1],
...operation.entity.ends?.[0],
}
]
} as SemanticModelRelationshipUsage;

this.change({[operation.id]: updatedRelationship}, []);
return {
success: true,
};
}

return {
success: false,
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
import {
isSemanticModelClass,
isSemanticModelGeneralization,
isSemanticModelRelationship,
LanguageString,
SemanticModelClass,
SemanticModelEntity,
Expand All @@ -12,6 +9,7 @@ import * as N3 from "n3";
import {DataFactory, Quad_Predicate, Quad_Subject} from "n3";
import namedNode = DataFactory.namedNode;
import literal = DataFactory.literal;
import {isSemanticModelClass, isSemanticModelGeneralization, isSemanticModelRelationship} from "../concepts";


function simpleIdSort(a: SemanticModelEntity, b: SemanticModelEntity) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import {Entity} from "../../../entity-model";
import {SemanticModelClassUsage, SemanticModelRelationshipUsage} from "./concepts";

export const SEMANTIC_MODEL_RELATIONSHIP_USAGE = "relationship-usage";
export const SEMANTIC_MODEL_CLASS_USAGE = "class-usage";

export function isSemanticModelRelationshipUsage(resource: Entity | null): resource is SemanticModelRelationshipUsage {
return resource?.type.includes(SEMANTIC_MODEL_RELATIONSHIP_USAGE) ?? false;
}

export function isSemanticModelClassUsage(resource: Entity | null): resource is SemanticModelClassUsage {
return resource?.type.includes(SEMANTIC_MODEL_CLASS_USAGE) ?? false;
}
49 changes: 49 additions & 0 deletions packages/core-v2/src/semantic-model/usage/concepts/concepts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import {Entity} from "../../../entity-model";
import {LanguageString, NamedThing} from "../../concepts/concepts";
import {SEMANTIC_MODEL_CLASS_USAGE, SEMANTIC_MODEL_RELATIONSHIP_USAGE} from "./concepts-utils";

type Nullable<T> = {
[P in keyof T]: P | null;
}

interface WithUsageNote {
/**
* Additional information about the usage of the entity.
*/
usageNote: LanguageString | null;
}

/**
* Usage semantically works as a subentity (subclass, subproperty), but is treated differently. Its public IRI is the
* same as IRI of entity that is being used. Moreover, it should "shadow" the entity that is being used, because in the
* given context this is more appropriate description of the entity. Each entity may have multiple usages.
*/
export interface SemanticModelUsage extends Entity, WithUsageNote {
/**
* ID of the entity that is being used. Usage has same IRI as the entity that is being used.
*/
usageOf: string;
}

export interface SemanticModelRelationshipUsage extends SemanticModelUsage, Nullable<NamedThing> {
type: [typeof SEMANTIC_MODEL_RELATIONSHIP_USAGE];

ends: SemanticModelRelationshipEndUsage[];
}

interface SemanticModelRelationshipEndUsage extends Nullable<NamedThing>, WithUsageNote {
/**
* Must be stricter or equal to the corresponding cardinality of the used entity.
*/
cardinality: [number, number|null] | null;

/**
* Must be descendant or self of the corresponding concept of the used entity.
* @todo is null default or no entity?
*/
concept: string | null;
}

export interface SemanticModelClassUsage extends SemanticModelUsage, Nullable<NamedThing> {
type: [typeof SEMANTIC_MODEL_CLASS_USAGE];
}
2 changes: 2 additions & 0 deletions packages/core-v2/src/semantic-model/usage/concepts/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from "./concepts";
export * from "./concepts-utils";
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './operations';
Loading

0 comments on commit 611da10

Please sign in to comment.