lincd
Version:
LINCD is a JavaScript library for building user interfaces with linked data (also known as 'structured data', or RDF)
1,041 lines • 125 kB
JavaScript
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var Pet_1, Person_1;
import { linkedComponent, linkedSetComponent, linkedShape, } from '../../package.js';
import { Shape } from '../../shapes/Shape.js';
import { literalProperty, objectProperty } from '../../shapes/SHACL.js';
import { Literal, NamedNode } from '../../models.js';
import { xsd } from '../../ontologies/xsd.js';
import { TestNode } from '../../utils/TraceShape.js';
import { describe, expect, test } from '@jest/globals';
import { render, waitFor } from '@testing-library/react';
import { ShapeSet } from '../../collections/ShapeSet.js';
import { setDefaultPageLimit } from '../../utils/Package.js';
import React from 'react';
import { getQueryContext, setQueryContext } from '../../queries/QueryContext.js';
let dogClass = NamedNode.getOrCreate(NamedNode.TEMP_URI_BASE + 'Dog');
let petClass = NamedNode.getOrCreate(NamedNode.TEMP_URI_BASE + 'Pet');
let personClass = NamedNode.getOrCreate(NamedNode.TEMP_URI_BASE + 'Person');
let name = NamedNode.getOrCreate(NamedNode.TEMP_URI_BASE + 'name');
let nickName = NamedNode.getOrCreate(NamedNode.TEMP_URI_BASE + 'nickName');
let bestFriend = NamedNode.getOrCreate(NamedNode.TEMP_URI_BASE + 'bestFriend');
let hobby = NamedNode.getOrCreate(NamedNode.TEMP_URI_BASE + 'hobby');
let hasFriend = NamedNode.getOrCreate(NamedNode.TEMP_URI_BASE + 'hasFriend');
let birthDate = NamedNode.getOrCreate(NamedNode.TEMP_URI_BASE + 'birthDate');
let owner = NamedNode.getOrCreate(NamedNode.TEMP_URI_BASE + 'owner');
let guardDogLevel = NamedNode.getOrCreate(NamedNode.TEMP_URI_BASE + 'guardDogLevel');
let hasPet = NamedNode.getOrCreate(NamedNode.TEMP_URI_BASE + 'hasPet');
let isRealPerson = NamedNode.getOrCreate(NamedNode.TEMP_URI_BASE + 'isRealPerson');
let pluralTestProp = NamedNode.getOrCreate(NamedNode.TEMP_URI_BASE + 'pluralTestProp');
let Pet = Pet_1 = class Pet extends Shape {
get bestFriend() {
return this.getOneAs(bestFriend, Pet_1);
}
set bestFriend(val) {
this.overwrite(bestFriend, val.namedNode);
}
};
Pet.targetClass = petClass;
__decorate([
objectProperty({
path: bestFriend,
maxCount: 1,
shape: Pet,
}),
__metadata("design:type", Pet),
__metadata("design:paramtypes", [Pet])
], Pet.prototype, "bestFriend", null);
Pet = Pet_1 = __decorate([
linkedShape
], Pet);
export { Pet };
let Person = Person_1 = class Person extends Shape {
get name() {
return this.getValue(name);
}
set name(val) {
this.overwrite(name, new Literal(val));
}
get bestFriend() {
return this.getOneAs(bestFriend, Person_1);
}
set bestFriend(val) {
this.overwrite(bestFriend, val.namedNode);
}
get hobby() {
return this.getValue(hobby);
}
set hobby(val) {
this.overwrite(hobby, new Literal(val));
}
get friends() {
return this.getAllAs(hasFriend, Person_1);
}
get pets() {
return this.getAllAs(hasPet, Pet);
}
get firstPet() {
return this.getOneAs(hasPet, Pet);
}
set firstPet(val) {
this.overwrite(hasPet, val.namedNode);
}
get pluralTestProp() {
return this.getAllAs(pluralTestProp, Person_1);
}
get birthDate() {
return this.hasProperty(birthDate)
? toNativeDate(this.getOne(birthDate))
: null;
}
set birthDate(nativeDate) {
this.overwrite(birthDate, fromNativeDate(nativeDate));
}
get isRealPerson() {
return this.hasProperty(isRealPerson) ? this.getValue(isRealPerson) === 'true' : undefined;
}
set isRealPerson(val) {
this.overwrite(isRealPerson, new Literal(val ? 'true' : 'false', xsd.boolean));
}
};
Person.targetClass = personClass;
__decorate([
literalProperty({
path: name,
maxCount: 1,
}),
__metadata("design:type", String),
__metadata("design:paramtypes", [String])
], Person.prototype, "name", null);
__decorate([
objectProperty({
path: bestFriend,
maxCount: 1,
shape: Person,
}),
__metadata("design:type", Person),
__metadata("design:paramtypes", [Person])
], Person.prototype, "bestFriend", null);
__decorate([
literalProperty({
path: hobby,
maxCount: 1,
}),
__metadata("design:type", String),
__metadata("design:paramtypes", [String])
], Person.prototype, "hobby", null);
__decorate([
objectProperty({
path: hasFriend,
shape: Person,
}),
__metadata("design:type", Object),
__metadata("design:paramtypes", [])
], Person.prototype, "friends", null);
__decorate([
objectProperty({
path: hasPet,
shape: Pet,
}),
__metadata("design:type", Object),
__metadata("design:paramtypes", [])
], Person.prototype, "pets", null);
__decorate([
objectProperty({
path: hasPet,
shape: Pet,
maxCount: 1,
}),
__metadata("design:type", Pet),
__metadata("design:paramtypes", [Pet])
], Person.prototype, "firstPet", null);
__decorate([
objectProperty({
path: pluralTestProp,
shape: Person,
}),
__metadata("design:type", Object),
__metadata("design:paramtypes", [])
], Person.prototype, "pluralTestProp", null);
__decorate([
literalProperty({
path: birthDate,
datatype: xsd.dateTime,
maxCount: 1,
}),
__metadata("design:type", Date),
__metadata("design:paramtypes", [Date])
], Person.prototype, "birthDate", null);
__decorate([
literalProperty({
path: isRealPerson,
datatype: xsd.boolean,
maxCount: 1,
}),
__metadata("design:type", Boolean),
__metadata("design:paramtypes", [Boolean])
], Person.prototype, "isRealPerson", null);
Person = Person_1 = __decorate([
linkedShape
], Person);
export { Person };
let Dog = class Dog extends Pet {
get guardDogLevel() {
return this.hasProperty(guardDogLevel) ? parseInt(this.getValue(guardDogLevel)) : undefined;
}
set guardDogLevel(val) {
this.overwrite(guardDogLevel, new Literal(val.toString(), xsd.integer));
}
};
Dog.targetClass = dogClass;
__decorate([
literalProperty({
path: guardDogLevel,
maxCount: 1,
datatype: xsd.integer,
}),
__metadata("design:type", Number),
__metadata("design:paramtypes", [Number])
], Dog.prototype, "guardDogLevel", null);
Dog = __decorate([
linkedShape
], Dog);
export { Dog };
function fromNativeDate(nativeDate) {
if (!nativeDate)
return null;
var value = nativeDate.toISOString();
return new Literal(value, xsd.dateTime);
}
function toNativeDate(literal) {
return literal
? new Date(literal instanceof TestNode ? null : literal.value)
: null;
}
let p1 = Person.getFromURI(NamedNode.TEMP_URI_BASE + 'p1-semmy');
p1.name = 'Semmy';
p1.birthDate = new Date('1990-01-01');
p1.set(nickName, new Literal('Sem1'));
p1.set(nickName, new Literal('Sem'));
let p2 = Person.getFromURI(NamedNode.TEMP_URI_BASE + 'p2-moa');
p2.name = 'Moa';
p2.hobby = 'Jogging';
let p3 = Person.getFromURI(NamedNode.TEMP_URI_BASE + 'p3-jinx');
p3.name = 'Jinx';
let p4 = Person.getFromURI(NamedNode.TEMP_URI_BASE + 'p4-quinn');
p4.name = 'Quinn';
p1.friends.add(p2);
p1.friends.add(p3);
p2.bestFriend = p3;
p2.friends.add(p3);
p2.friends.add(p4);
p1.pluralTestProp.add(p1);
p1.pluralTestProp.add(p2);
p1.pluralTestProp.add(p3);
p1.pluralTestProp.add(p4);
p1.isRealPerson = true;
p2.isRealPerson = false;
p3.isRealPerson = true;
let dog1 = Dog.getFromURI(NamedNode.TEMP_URI_BASE + 'dog1');
dog1.guardDogLevel = 2;
let dog2 = Dog.getFromURI(NamedNode.TEMP_URI_BASE + 'dog2');
dog1.bestFriend = dog2;
p1.pets.add(dog1);
p2.pets.add(dog2);
//kind of a duplicate (it replaces previously set pets), but helpful for testing .as() on singular values
p1.firstPet = dog1;
export const testEntities = [p1, p2, p3, p4, dog1, dog2];
export const testProps = { name, nickName, bestFriend, hobby, hasFriend, birthDate };
export const testTypes = { person: personClass };
setQueryContext('user', p3, Person);
/**
*
* @param startPromise if provided it will be awaited before running the tests
*/
export const runQueryTests = (startPromise = Promise.resolve()) => {
describe('query tests', () => {
describe('1. Basic Property Selection', () => {
test('can select a literal property of all instances', () => __awaiter(void 0, void 0, void 0, function* () {
yield startPromise;
// x:LinkedQuery<Person, QueryString<Person, "name">>
let names = yield Person.select((p) => {
let res = p.name;
return res;
});
// let names = resolveLocal(x);
/**
* Expected result:
* [{
* "id:"..."
* "shape": a Person
* "name:"Semmy"
* },{
* "name":"Moa",
* },... ]
*/
names.forEach((name) => {
});
expect(Array.isArray(names)).toBe(true);
expect(names.length).toBe(4);
expect(typeof names[0] === 'object').toBe(true);
expect(names[0].hasOwnProperty('name')).toBe(true);
expect(names[0].name).toBe('Semmy');
expect(names[0].id).toBe(p1.uri);
}));
test('can select an object property of all instances', () => __awaiter(void 0, void 0, void 0, function* () {
// x:LinkedQuery<Person, QueryString<Person, "name">>
// QueryShapeSet<Person, Person, "friends"> & ToQueryShapeSetValue<QueryShapeSet<Person, Person, "friends">, Person, "friends">
//Needs to become:
// -> QResult<Person, {friends: QResult<Person, {}>[]}>[]
//From person the property friends is requested.
//The results is a shapeset of persons, with source Person
//S / ShapeType: Person
//Source:Person
//Property: "friends"
//Shapeset turns into QResult<Person,{friends:QResult<Person,{}>[]}> ... thats just the shapeset
//then
let personFriends = yield Person.select((p) => {
let res = p.friends;
return res;
});
/**
* Expected result:
* [{
* "id:"..."
* "shape": a Person
* "friends:[{
* "id"...,
* "shape": a Person
* },...]
* },... ]
*/
let firstResult = personFriends[0];
expect(Array.isArray(personFriends)).toBe(true);
expect(personFriends.length).toBe(4);
expect(typeof personFriends[0] === 'object').toBe(true);
expect(firstResult.hasOwnProperty('id')).toBe(true);
expect(firstResult.id).toBe(p1.uri);
expect(firstResult.friends.length).toBe(2);
expect(firstResult.friends[0].id).toBe(p2.uri);
expect(firstResult.friends[1].id).toBe(p3.uri);
}));
test('can select a date', () => __awaiter(void 0, void 0, void 0, function* () {
let birthDates = yield Person.select((p) => {
return [p.birthDate, p.name];
});
let firstResult = birthDates[0];
expect(Array.isArray(birthDates)).toBe(true);
expect(birthDates.length).toBe(4);
expect(typeof firstResult.birthDate === 'object').toBe(true);
expect(firstResult.birthDate.toString()).toBe(p1.birthDate.toString());
}));
test('can select a boolean', () => __awaiter(void 0, void 0, void 0, function* () {
let isRealPersons = yield Person.select((p) => {
return p.isRealPerson;
});
expect(Array.isArray(isRealPersons)).toBe(true);
expect(isRealPersons.length).toBe(4);
expect(isRealPersons.filter(p => p.isRealPerson !== null).length).toBe(3);
let p1Result = isRealPersons.find(p => p.id === p1.uri);
expect(p1Result.isRealPerson).toBe(true);
let p2Result = isRealPersons.find(p => p.id === p2.uri);
expect(p2Result.isRealPerson).toBe(false);
let p4Result = isRealPersons.find(p => p.id === p4.uri);
expect(p4Result.isRealPerson).toBeNull();
}));
test('can select properties of a specific subject', () => __awaiter(void 0, void 0, void 0, function* () {
let qRes = yield Person.select(p1, p => p.name);
expect(qRes.name).toBe(p1.name);
expect(qRes.id).toBe(p1.uri);
}));
test('can select properties of a specific subject by ID reference', () => __awaiter(void 0, void 0, void 0, function* () {
let qRes = yield Person.select({ id: p1.uri }, p => p.name);
expect(qRes.name).toBe(p1.name);
expect(qRes.id).toBe(p1.uri);
}));
test('select with a non existing returns null', () => __awaiter(void 0, void 0, void 0, function* () {
let qRes = yield Person.select({ id: 'https://does.not/exist' }, p => p.name);
expect(qRes).toBeNull();
}));
});
describe('2. Nested & Path Selection', () => {
test('can select sub properties of a first property that returns a set', () => __awaiter(void 0, void 0, void 0, function* () {
let namesOfFriends = yield Person.select((p) => {
// QueryString<QueryShapeSet<Person, Person, "friends">, "name">
//step 1) --> QResult<QueryShapeSet<Person, Person, "friends">, {name: string}>[][]
//step 2) --> QResult<Person, {friends: QResult<Person, {name: string}>}>[][]
//--> QResult<Person, {friends: QResult<Person, {name:string}>}>[]
//QueryString<QueryShapeSet<Person, Person, "friends">, "name">
//Source : QueryShapeSet<Person, Person, "friends">
//Property: "name"
// QueryShapeSet<Person, Person, "friends">
// ShapeType : Person
// Source: Person
// Property: "friends
// in other words. Person.friends is a set of persons
//which needs to be converted to QResult<Person (Source), friends: is a QResult<Person (ShapeType),{name:string}> array
let res = p.friends.name;
return res;
});
let first = namesOfFriends[0];
expect(Array.isArray(namesOfFriends)).toBe(true);
expect(namesOfFriends.length).toBe(4);
expect(first.id).toBe(p1.uri);
expect(first.friends.length).toBe(2);
expect(first.friends[0].id).toBe(p2.uri);
expect(first.friends[0].name).toBe('Moa');
expect(first.friends[0]['hobby']).toBeUndefined();
}));
test('can select a nested set of shapes', () => __awaiter(void 0, void 0, void 0, function* () {
let friendsOfFriends = yield Person.select((p) => {
return p.friends.friends;
});
expect(Array.isArray(friendsOfFriends)).toBe(true);
let first = friendsOfFriends[0];
expect(friendsOfFriends.length).toBe(4);
expect(first.friends.length).toBe(2);
expect(first.friends[0].friends.some((f) => f.id == p3.uri)).toBe(true);
expect(first.friends[0].friends.some((f) => f.id == p4.uri)).toBe(true);
expect(first.friends[1].friends.length).toBe(0);
expect(friendsOfFriends[3].friends.length).toBe(0);
}));
test('can select multiple property paths', () => __awaiter(void 0, void 0, void 0, function* () {
let result = yield Person.select((p) => {
let res = [p.name, p.friends, p.bestFriend.name];
return res;
});
expect(Array.isArray(result)).toBe(true);
expect(result.length).toBe(4);
let first = result[0];
expect(first.name).toBe('Semmy');
expect(Array.isArray(first.friends)).toBe(true);
expect(first.friends.length).toBe(2);
expect(first.friends.some((f) => f.id === p2.uri)).toBe(true);
expect(first.friends.some((f) => f.id === p4.uri)).toBe(false);
}));
test('can select property of single shape value', () => __awaiter(void 0, void 0, void 0, function* () {
//(
// QResult<Person, {bestFriend: QResult<Person, {name: string}>}> |
// QResult<Shape, {}> |
// QResult<...>[]
// )[]
//QResult<Person, {bestFriend: QResult<Person>}>[]
//QResult<Person, {bestFriend: QResult<Person, {name: string}>}>
// |QResult<Shape, {}> |QResult<...>[])[]QResult<Person, {bestFriend: QResult<Person>}>[]
let result = yield Person.select((p) => {
// QShape<Person, QShape<Person, null, "">, "bestFriend">
let r = p.bestFriend.name;
// let r3 = [p.bestFriend];
// let r2 = [p.friends.friends.name];
return r;
});
//expected result:
/**
* [
* {
* "id": "p1",
* "bestFriend": {
* "id": "p3",
* "name": "Jinx"
* }
* ...
* ]
*/
expect(Array.isArray(result)).toBe(true);
expect(result.length).toBe(4);
let second = result[1];
expect(second.bestFriend.id).toBe(p3.uri);
}));
test('can select 3 level deep nested paths', () => __awaiter(void 0, void 0, void 0, function* () {
let level3Friends = yield Person.select((p) => {
return p.friends.friends.friends;
});
expect(level3Friends.length).toBe(4);
expect(level3Friends.every((p) => p.friends.every((f) => f.friends.every((f2) => f2.friends.length === 0)))).toBe(true);
}));
});
describe('3. Filtering (Where Clauses)', () => {
test('can use where() to filter a string in a set of Literals with equals', () => __awaiter(void 0, void 0, void 0, function* () {
//we select the friends of all persons, but only those friends whose name is moa
//this will return an array, where each entry represents the results for a single person.
// the entry contains those friends of the person whose name is Moa - (as a set of persons)
//QResult<Person, {friends: QResult<Person, {}>[]}>[]
let friendsCalledMoa = yield Person.select((p) => {
return p.friends.where((f) => f.name.equals('Moa'));
});
let first = friendsCalledMoa[0];
let second = friendsCalledMoa[1];
expect(Array.isArray(friendsCalledMoa)).toBe(true);
expect(first.friends.length).toBe(1);
expect(first.friends[0].id).toBe(p2.uri);
expect(second.friends.length).toBe(0);
}));
test('where object value', () => __awaiter(void 0, void 0, void 0, function* () {
//we select the friends of all persons, but only those friends whose name is moa
//this will return an array, where each entry represents the results for a single person.
// the entry contains those friends of the person whose name is Moa - (as a set of persons)
//QResult<Person, {friends: QResult<Person, {}>[]}>[]
let hasBestFriend = yield Person.select().where(p => {
return p.bestFriend.equals({ id: p3.uri });
});
expect(Array.isArray(hasBestFriend)).toBe(true);
expect(hasBestFriend.length).toBe(1);
expect(hasBestFriend[0].id).toBe(p2.uri);
}));
test('where on literal', () => __awaiter(void 0, void 0, void 0, function* () {
const hobbies = yield Person.select((p) => {
return p.hobby.where(h => h.equals(p2.hobby));
});
expect(Array.isArray(hobbies)).toBe(true);
expect(hobbies.length).toBe(4);
let p1Result = hobbies.find(h => h.id === p1.uri);
let p2Result = hobbies.find(h => h.id === p2.uri);
expect(p1Result).toBeDefined();
expect(p2Result).toBeDefined();
expect(p1Result.hobby).toBeUndefined();
expect(p2Result.hobby).toBe(p2.hobby);
}));
test('where and', () => __awaiter(void 0, void 0, void 0, function* () {
//we select the friends of all persons, but only those friends whose name is moa
//this will return an array, where each entry represents the results for a single person.
// the entry contains those friends of the person whose name is Moa - (as a set of persons)
let friendsCalledMoaThatJog = yield Person.select((p) => {
return p.friends.where((f) => f.name.equals('Moa').and(f.hobby.equals('Jogging')));
});
let first = friendsCalledMoaThatJog[0];
let second = friendsCalledMoaThatJog[1];
expect(Array.isArray(friendsCalledMoaThatJog)).toBe(true);
expect(first.friends.length).toBe(1);
expect(first.friends[0].id).toBe(p2.uri);
expect(second.friends.length).toBe(0);
}));
test('where or', () => __awaiter(void 0, void 0, void 0, function* () {
//we select the friends of all persons, but only those friends whose name is moa
//this will return an array, where each entry represents the results for a single person.
// the entry contains those friends of the person whose name is Moa - (as a set of persons)
let orFriends = yield Person.select((p) => {
return p.friends.where((f) => f.name.equals('Jinx').or(f.hobby.equals('Jogging')));
});
let first = orFriends[0];
let second = orFriends[1];
expect(Array.isArray(orFriends)).toBe(true);
expect(first.friends.length).toBe(2);
expect(first.friends[0].id).toBe(p2.uri);
expect(first.friends[1].id).toBe(p3.uri);
expect(second.friends.length).toBe(1);
expect(second.friends[0].id).toBe(p3.uri);
}));
test('select all', () => __awaiter(void 0, void 0, void 0, function* () {
let all = yield Person.select();
expect(Array.isArray(all)).toBe(true);
expect(all.length).toBe(4);
}));
test('empty select with where ', () => __awaiter(void 0, void 0, void 0, function* () {
let filteredNoProps = yield Person.select().where((p) => {
return p.name.equals(p1.name);
});
expect(Array.isArray(filteredNoProps)).toBe(true);
expect(filteredNoProps.length).toBe(1);
expect(filteredNoProps[0].id).toBe(p1.uri);
}));
test('where and or and', () => __awaiter(void 0, void 0, void 0, function* () {
//we combine AND & OR. AND should be done first, then OR
//Boolean logic, AND always comes before OR
//friend.name === A || friend.hobby === B && friend.name === C
//Therefor we expect p2 and p3 to match as friends
//(p3 would not match if the OR was done first)
let persons = yield Person.select((p) => {
return p.friends.where((f) => f.name
.equals('Jinx')
.or(f.hobby.equals('Jogging'))
.and(f.name.equals('Moa')));
});
//test the same thing again, but now the and clause is done within the or clause
//the result should be the same
let persons2 = yield Person.select((p) => {
return p.friends.where((f) => f.name
.equals('Jinx')
.or(f.hobby.equals('Jogging').and(f.name.equals('Moa'))));
});
//(friend.name === A || friend.hobby === B) && friend.name === C
// let persons3 = await Person.select((p) => {
// return p.friends.where((f) =>
// f.name.equals('Moa').and(
// f.name.equals('Jinx')
// .or(f.hobby.equals('Jogging')),
// )
// );
// });
//TODO: implement f.or(A,B)
[persons, persons2].forEach((result) => {
expect(Array.isArray(result)).toBe(true);
expect(result[0].friends.length).toBe(2);
expect(result[1].friends.length).toBe(1);
expect(result[2].friends.length).toBe(0);
expect(result[3].friends.length).toBe(0);
expect(result[0].friends[0].id).toBe(p2.uri);
expect(result[0].friends[1].id).toBe(p3.uri);
expect(result[1].friends[0].id).toBe(p3.uri);
});
}));
test('where some implicit', () => __awaiter(void 0, void 0, void 0, function* () {
//select all persons that have a friend called Moa
//the test relies on the fact that by default, some() is applied.
//in other words, the person matches if at least 1 friend is called Moa
let peopleWithFriendsCalledMoa = yield Person.select().where((p) => {
return p.friends.name.equals('Moa');
});
expect(Array.isArray(peopleWithFriendsCalledMoa)).toBe(true);
expect(peopleWithFriendsCalledMoa.length).toBe(1);
expect(peopleWithFriendsCalledMoa[0].id).toBe(p1.uri);
}));
test('where some explicit', () => __awaiter(void 0, void 0, void 0, function* () {
// same as last test but with explicit some()
let peopleWithFriendsCalledMoa = yield Person.select().where((p) => {
return p.friends.some((f) => {
return f.name.equals('Moa');
});
});
expect(Array.isArray(peopleWithFriendsCalledMoa)).toBe(true);
expect(peopleWithFriendsCalledMoa.length).toBe(1);
expect(peopleWithFriendsCalledMoa[0].id).toBe(p1.uri);
}));
test('where every', () => __awaiter(void 0, void 0, void 0, function* () {
// select people that only have friends that are called Moa or Jinx
let allFriendsCalledMoaOrJinx = yield Person.select().where((p) => {
return p.friends.every((f) => {
return f.name.equals('Moa').or(f.name.equals('Jinx'));
});
});
expect(Array.isArray(allFriendsCalledMoaOrJinx)).toBe(true);
expect(allFriendsCalledMoaOrJinx.length).toBe(1);
expect(allFriendsCalledMoaOrJinx[0].id).toBe(p1.uri);
}));
test('where sequences', () => __awaiter(void 0, void 0, void 0, function* () {
// select people that have a friend called Jinx and a name "Semmy" (so that's only p1)
//Should be QResult<Person, {name:string}>[]
let friendCalledJinxAndNameIsSemmy = yield Person.select().where((p) => {
let res = p.friends
.some((f) => {
return f.name.equals('Jinx');
})
.and(p.name.equals('Semmy'));
return res;
});
expect(Array.isArray(friendCalledJinxAndNameIsSemmy)).toBe(true);
expect(friendCalledJinxAndNameIsSemmy.length).toBe(1);
expect(friendCalledJinxAndNameIsSemmy[0].id).toBe(p1.uri);
// select people that have a friend called Jinx, BUT ONLY SELECT THEIR NAME if their name is "Semmy"
//so we should get p1 and p2 (the outher .where filters 4 down to 2), but only the name of p1 should be defined
let friendCalledJinxAndNameIsSemmy2 = yield Person.select((p) => {
let res = p.name.where((n) => {
return n.equals('Semmy');
});
return res;
}).where((p) => p.friends.some((f) => {
return f.name.equals('Jinx');
}));
//make sure type is undefined. Then make everything with single shapes work only with QResult
expect(Array.isArray(friendCalledJinxAndNameIsSemmy2)).toBe(true);
expect(friendCalledJinxAndNameIsSemmy2.length).toBe(2);
expect(friendCalledJinxAndNameIsSemmy2[0].id).toBe(p1.uri);
expect(friendCalledJinxAndNameIsSemmy2[1].id).toBe(p2.uri);
expect(friendCalledJinxAndNameIsSemmy2[0].name).toBe('Semmy');
expect(typeof friendCalledJinxAndNameIsSemmy2[1].name).toBe('undefined');
}));
test('outer where()', () => __awaiter(void 0, void 0, void 0, function* () {
// QResult<Person, {friends: QResult<Person, {}>[]}>[]
let friendsOfP1 = yield Person.select((p) => {
return p.friends;
}).where((p) => {
return p.name.equals(p1.name);
});
let first = friendsOfP1[0];
expect(Array.isArray(friendsOfP1)).toBe(true);
expect(friendsOfP1).toHaveLength(1);
expect(first.id).toBe(p1.uri);
expect(first.friends.length).toBe(2);
expect(first.friends[0].id).toBe(p2.uri);
}));
test('where with query context', () => __awaiter(void 0, void 0, void 0, function* () {
//should return name of p2
let namesHasBestFriendUser = yield Person.select((p) => {
return p.name;
}).where((p) => {
return p.bestFriend.equals(getQueryContext('user'));
});
expect(Array.isArray(namesHasBestFriendUser)).toBe(true);
let first = namesHasBestFriendUser[0];
expect(namesHasBestFriendUser).toHaveLength(1);
expect(first.id).toBe(p2.uri);
expect(first.name).toBe(p2.name);
}));
test('where with query context as base of property path', () => __awaiter(void 0, void 0, void 0, function* () {
//should return name of p2
let hasUserAsFriend = yield Person.select((p) => {
return p.name;
}).where((p) => {
const userName = getQueryContext('user').name;
return p.friends.some(f => f.name.equals(userName));
});
expect(Array.isArray(hasUserAsFriend)).toBe(true);
expect(hasUserAsFriend).toHaveLength(2);
expect(hasUserAsFriend.some(p => p.id === p1.uri && p.name === p1.name)).toBeTruthy();
expect(hasUserAsFriend.some(p => p.id === p2.uri && p.name === p2.name)).toBeTruthy();
}));
});
describe('4. Aggregation & Sub-Select', () => {
test('count a shapeset', () => __awaiter(void 0, void 0, void 0, function* () {
//count the number of friends that each person has
//QResult<Person, {friends: number}>[]
let numberOfFriends = yield Person.select((p) => {
let res = p.friends.size();
return res;
});
//Note that when no argument is given to count, we expect the key to be the label of the
// last property before count. So that's "friends"
//expected result
/**
* [{
* id: "p1",
* friends: 2
* },{
* id: "p2",
* friends: 2
* },...]
*/
expect(Array.isArray(numberOfFriends)).toBe(true);
expect(numberOfFriends[0].friends).toBe(2);
expect(numberOfFriends[1].friends).toBe(2);
expect(numberOfFriends[2].friends).toBe(0);
expect(numberOfFriends[3].friends).toBe(0);
}));
test('count a nested property', () => __awaiter(void 0, void 0, void 0, function* () {
//count the number of friends that each person has
//QResult<Person, {friends: number}>[]
let numberOfFriends = yield Person.select((p) => {
let res = p.friends.friends.size();
//TODO: count() -> let res = p.count(friends.friends); --> would return the total sum of friends of friends
return res;
});
//expected result
/**
* [{
* id: "p1",
* friends: [{
* id: "p2",
* friends: 2
* },{
* id: "p3",
* friends: 0
* }]
* },...]
*/
expect(Array.isArray(numberOfFriends)).toBe(true);
expect(Array.isArray(numberOfFriends[0].friends)).toBe(true);
expect(numberOfFriends[0].friends[0].friends).toBe(2);
expect(numberOfFriends[0].friends[1].friends).toBe(0);
}));
// test('shape.count() with a countable argument', async () => {
// //count the number of friends that each person has
// //QResult<Person, {friends: number}>[]
// let numberOfFriends = await Person.select((p) => {
// let res = p.count(p.friends);
//
// return res;
// });
// //expected result
// /**
// * [{
// * id: "p1",
// * count: 2
// * },{
// * id: "p2",
// * count: 2
// * },...]
// */
//
// expect(Array.isArray(numberOfFriends)).toBe(true);
// expect(numberOfFriends[0].count).toBe(2);
// expect(numberOfFriends[1].count).toBe(2);
// expect(numberOfFriends[2].count).toBe(0);
// expect(numberOfFriends[3].count).toBe(0);
// });
test('labeling the key of count()', () => __awaiter(void 0, void 0, void 0, function* () {
//count the number of friends that each person has
let numberOfFriends3 = yield Person.select((p) => {
let res = p.friends.select((f) => ({ numFriends: f.friends.size() }));
return res;
});
//expected result
/**
* [{
* id: "p1",
* friends: [
* {numFriends: 2,id: "p2"},
* {numFriends: 0,id: "p3"}
* ]
* },{
* id: "p2",
* friends: [
* {numFriends: 0,id: "p3"},
* {numFriends: 0,id: "p4"}
* ]
* },...]
*/
//We want outcome to be {numFriends: number}
//So ObjectToPlainResult should convert the SetSize to a number
//if Source (SetSize<Source>) extends QueryShapeSet, then its an object, else a number
//SelectQueryFactory<
// Person,
// {
// numFriends: SetSize<QShapeSet<Person,QShape<Person,null,''>,'friends'>>
// },
// QueryShapeSet<Person,QShape<Person,null,''>,'friends'>
//>
//
//Step 1: QueryResponseToResultType
// SelectQueryFactory extends GetNestedQueryResultType<
// any
// Response = {numFriends: SetSize<QShapeSet<Person,QShape<Person,null,''>,'friends'>>
// Source = QueryShapeSet<Person,QShape<Person,null,''>,'friends'>
//Step 2: GetNestedQueryResultType
//Source extends QueryBuilderObject<Source, Response>
//Step 3: GetQueryObjectResultType<
//QV = Source = QueryShapeSet<Person,QShape<Person,null,''>,'friends'>
//SubProperties = ResponseToObject<Response>
//QV extends QueryShapeSet<
//ShapeType = Person
//Source = QShape<Person,null,''>
//Property = 'friends'
//Step 4: CreateShapeSetQResult<
//ShapeType=ShapeType=Person,
//Source=QShape<Person,null,''>,
//Property='friends,
//SubProperties=ResponseToObject<Response>
//HasName=false
//>
//Source extends QueryShape<
//SourceShapeType = Person
//ParentSource = null
//> -> QResult<
// SourceShapeType=Person,
// {[P in Property='friends']: CreateQResult<Source, null, null, SubProperties>[]}
// >
//Step 5: CreateQResult<
// Source=QShape<Person,null,''>
// Value=null,
// Property=null,
// SubProperties=ResponseToObject<Response>
//>
//Source extends QShape<
// SourceShapeType = Person
// ParentSource = null
// SourceProperty = ''
let first = numberOfFriends3[0];
let firstNumFriends = first.friends[0].numFriends;
// let firstNumFriends: number = first.friends;
expect(first.hasOwnProperty('friends')).toBe(true);
expect(first.hasOwnProperty('count')).toBe(false);
expect(firstNumFriends).toBe(2);
}));
// test('count a nested path as argument', async () => {
// //count the number of second level friends that each person has
// //count is expected to count the total number of final nodes (friends) in the p.friends.friends set
// //by counting each sub result and combinging the results
// let numberOfFriends = await Person.select((p) => {
// let res = p.count(p.friends.friends, 'numFriends');
// return res;
// });
// //expected result
// /**
// * [{
// * id: "p1",
// * count: 2
// * },{
// * id: "p2",
// * count: 0
// * },...]
// */
//
// let first = numberOfFriends[0];
// expect(Array.isArray(numberOfFriends)).toBe(true);
// expect(numberOfFriends[0].count).toBe(2);
// expect(numberOfFriends[1].count).toBe(0);
// expect(numberOfFriends[2].count).toBe(0);
// expect(numberOfFriends[3].count).toBe(0);
// });
test('nested object property', () => __awaiter(void 0, void 0, void 0, function* () {
//NOTE: this test is currently just here for typescript types.
let res = yield Person.select((p) => {
let res = {
friends: p.friends,
bestFriends: p.friends.bestFriend,
};
return res;
});
//({firstName,lastName}) => {
// return <div>...</div>
//}
//has to be an array of objects
let friends = res[0].friends;
//bestFriends should be a PATH, but it's not. Its a end result only
let bestFriends = res[0].bestFriends;
let res2 = yield Person.select((p) => {
let res = p.friends.bestFriend;
return res;
});
//This works, friends is an array and bestFriend is a single shape
let firstBestFriend = res2[0].friends[0].bestFriend;
}));
test('sub select single prop', () => __awaiter(void 0, void 0, void 0, function* () {
let bestFriendProps = yield Person.select((p) => {
let res = p.bestFriend.select((f) => {
let props = [f.name, f.hobby];
return props;
});
return res;
}).where(p => {
return p.equals({ id: p2.uri });
});
// SelectQueryFactory<
// Person,
// (
// QueryString<QueryShape<Person, null, ""> & QueryShapeProps<Person, null, "">, "name">|
// QueryString<QueryShape<Person, null, ""> & QueryShapeProps<Person, null, "">, "hobby">
// )[],
// QueryShape<
// Person,
// QueryShape<Person, null, ""> & QueryShapeProps<Person, null, "">,
// "bestFriend"
// >
// >
//step 1: GetNestedQueryResultType<Response, Source>
//Response = (
// QueryString<QueryShape<Person, null, ""> & QueryShapeProps<Person, null, "">, "name">|
// QueryString<QueryShape<Person, null, ""> & QueryShapeProps<Person, null, "">, "hobby">
//)[]
//Source = QueryShape<
// Person,
// QueryShape<Person, null, ""> & QueryShapeProps<Person, null, "">,
// "bestFriend"
// >
//Source extends QueryBuilderObject
//--> step 2: GetQueryObjectResultType<QV=Source, SubProperties=ResponseToObject<Response>
//QV extends QueryShape<ShapeType,Source,Property>
//ShapeType = Person (value type of property?)
//Source = QueryShape<Person, null, ""> & QueryShapeProps<Person, null, "">
//Property = "bestFriend"
//--> step3: CreateQResult<Source,ShapeType,Property,SubProperties,HasName=false>
//Source=Source=QueryShape<Person, null, ""> & QueryShapeProps<Person, null, ""> (original request Person.select())
//Value=ShapeType=Person (value type of property?)
//Property="bestFriend"
//SubProperties=ResponseToObject<Response>
//HasName=false
//Source extends QueryShape<SourceShapeType,ParentSource,SourceProperty>
//SourceShapeType = Person
//ParentSource = null
//SourceProperty = ''
//-->
//QResult<
// SourceShapeType=Person
// {
// [P in Property("bestFriend")]: CreateQResult<Value=ShapeType=Person,Value=ShapeType=Person>
// } & SubProperties
//CONFLICTING
//Step 5: CreateQResult<
// Source=QShape<Person,null,''>
// Value=null,
// Property=null,
// SubProperties=ResponseToObject<Response>
//>
//Source extends QShape<
// SourceShapeType = Person
// ParentSource = null
// SourceProperty = ''
//We want:
//QResult<
// Person,
// {
// bestFriend: QResult<Person, {
// name:string,
// hobby:string
// }>
// }
//>[]
/**
* Expected result:
* [{
* "id:"..."
* "bestFriend": {
* id:"...",
* name:"Jinx",
* hobby:undefined
* }
* }]
*/
let first = bestFriendProps[0];
// let name = first.bestFriend.name;
expect(Array.isArray(bestFriendProps)).toBe(true);
expect(bestFriendProps.length).toBe(1);
expect(first.id).toBe(p2.uri);
expect(first.bestFriend.id).toBe(p3.uri);
expect(first.bestFriend.name).toBe(p3.name);
expect(first.bestFriend.hobby).toBeNull();
}));
test('sub select plural prop - custom object', () => __awaiter(void 0, void 0, void 0, function* () {
let namesAndHobbiesOfFriends = yield Person.select((p) => {
let res = p.friends.select((f) => {
let res2 = {
_name: f.name,
_hobby: f.hobby,
};
return res2;
});
return res;
});
//
//LinkedQuery<Person,{
// _name: QueryString<QShape<Person,null,''>,'name'>
// _hobby: QueryString<QShape<Person,null,''>,'hobby'>
//},QueryShapeSet<...>>
//QShapeSet<Person,QShape<Person,null,''>,'friends'>
//GetNestedQueryResultType<
// Response = {name,hobby},
// Source = QShapeSet<Person,QShape<Person,null,''>,'friends'>
//>
// --> GetQueryObjectResultType<
// Source = QShapeSet<Person,QShape<Person,null,''>,'friends'>,
// SubProperties = ResponseToObject<{
// _name: QueryString<QShape<Person,null,''>,'name'>,
// _hobby: QueryString<QShape<Person,null,''>,'hobby'>
// }>
// >
//--> QV extends QueryShapeSet.. ->
// CreateShapeSetQResult<
// ShapeType = Person,
// Source = QShape<Person,null,''>,
// Property = 'friends',
// SubProperties = {}
// HasName = false? (we're currently not passing this in GetNestedQueryResultType)
//>
//-> QResult<
// Source = SourceShapeType = Person,
// {'friends': CreateQResult< Person, null, null, {_name: string, _hobby: string}>[]}
//