UNPKG

lincd

Version:

LINCD is a JavaScript library for building user interfaces with linked data (also known as 'structured data', or RDF)

962 lines (961 loc) 134 kB
"use strict"; 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 __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; var Pet_1, Person_1; Object.defineProperty(exports, "__esModule", { value: true }); exports.runQueryTests = exports.testTypes = exports.testProps = exports.testEntities = exports.Dog = exports.Person = exports.Pet = void 0; const package_js_1 = require("../../package.js"); const Shape_js_1 = require("../../shapes/Shape.js"); const SHACL_js_1 = require("../../shapes/SHACL.js"); const models_js_1 = require("../../models.js"); const xsd_js_1 = require("../../ontologies/xsd.js"); const TraceShape_js_1 = require("../../utils/TraceShape.js"); const globals_1 = require("@jest/globals"); const react_1 = require("@testing-library/react"); const ShapeSet_js_1 = require("../../collections/ShapeSet.js"); const Package_js_1 = require("../../utils/Package.js"); const react_2 = __importDefault(require("react")); const QueryContext_js_1 = require("../../queries/QueryContext.js"); let dogClass = models_js_1.NamedNode.getOrCreate(models_js_1.NamedNode.TEMP_URI_BASE + 'Dog'); let petClass = models_js_1.NamedNode.getOrCreate(models_js_1.NamedNode.TEMP_URI_BASE + 'Pet'); let personClass = models_js_1.NamedNode.getOrCreate(models_js_1.NamedNode.TEMP_URI_BASE + 'Person'); let name = models_js_1.NamedNode.getOrCreate(models_js_1.NamedNode.TEMP_URI_BASE + 'name'); let nickName = models_js_1.NamedNode.getOrCreate(models_js_1.NamedNode.TEMP_URI_BASE + 'nickName'); let bestFriend = models_js_1.NamedNode.getOrCreate(models_js_1.NamedNode.TEMP_URI_BASE + 'bestFriend'); let hobby = models_js_1.NamedNode.getOrCreate(models_js_1.NamedNode.TEMP_URI_BASE + 'hobby'); let hasFriend = models_js_1.NamedNode.getOrCreate(models_js_1.NamedNode.TEMP_URI_BASE + 'hasFriend'); let birthDate = models_js_1.NamedNode.getOrCreate(models_js_1.NamedNode.TEMP_URI_BASE + 'birthDate'); let owner = models_js_1.NamedNode.getOrCreate(models_js_1.NamedNode.TEMP_URI_BASE + 'owner'); let guardDogLevel = models_js_1.NamedNode.getOrCreate(models_js_1.NamedNode.TEMP_URI_BASE + 'guardDogLevel'); let hasPet = models_js_1.NamedNode.getOrCreate(models_js_1.NamedNode.TEMP_URI_BASE + 'hasPet'); let isRealPerson = models_js_1.NamedNode.getOrCreate(models_js_1.NamedNode.TEMP_URI_BASE + 'isRealPerson'); let pluralTestProp = models_js_1.NamedNode.getOrCreate(models_js_1.NamedNode.TEMP_URI_BASE + 'pluralTestProp'); let Pet = Pet_1 = class Pet extends Shape_js_1.Shape { get bestFriend() { return this.getOneAs(bestFriend, Pet_1); } set bestFriend(val) { this.overwrite(bestFriend, val.namedNode); } }; exports.Pet = Pet; Pet.targetClass = petClass; __decorate([ (0, SHACL_js_1.objectProperty)({ path: bestFriend, maxCount: 1, shape: Pet, }), __metadata("design:type", Pet), __metadata("design:paramtypes", [Pet]) ], Pet.prototype, "bestFriend", null); exports.Pet = Pet = Pet_1 = __decorate([ package_js_1.linkedShape ], Pet); let Person = Person_1 = class Person extends Shape_js_1.Shape { get name() { return this.getValue(name); } set name(val) { this.overwrite(name, new models_js_1.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 models_js_1.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 models_js_1.Literal(val ? 'true' : 'false', xsd_js_1.xsd.boolean)); } }; exports.Person = Person; Person.targetClass = personClass; __decorate([ (0, SHACL_js_1.literalProperty)({ path: name, maxCount: 1, }), __metadata("design:type", String), __metadata("design:paramtypes", [String]) ], Person.prototype, "name", null); __decorate([ (0, SHACL_js_1.objectProperty)({ path: bestFriend, maxCount: 1, shape: Person, }), __metadata("design:type", Person), __metadata("design:paramtypes", [Person]) ], Person.prototype, "bestFriend", null); __decorate([ (0, SHACL_js_1.literalProperty)({ path: hobby, maxCount: 1, }), __metadata("design:type", String), __metadata("design:paramtypes", [String]) ], Person.prototype, "hobby", null); __decorate([ (0, SHACL_js_1.objectProperty)({ path: hasFriend, shape: Person, }), __metadata("design:type", Object), __metadata("design:paramtypes", []) ], Person.prototype, "friends", null); __decorate([ (0, SHACL_js_1.objectProperty)({ path: hasPet, shape: Pet, }), __metadata("design:type", Object), __metadata("design:paramtypes", []) ], Person.prototype, "pets", null); __decorate([ (0, SHACL_js_1.objectProperty)({ path: hasPet, shape: Pet, maxCount: 1, }), __metadata("design:type", Pet), __metadata("design:paramtypes", [Pet]) ], Person.prototype, "firstPet", null); __decorate([ (0, SHACL_js_1.objectProperty)({ path: pluralTestProp, shape: Person, }), __metadata("design:type", Object), __metadata("design:paramtypes", []) ], Person.prototype, "pluralTestProp", null); __decorate([ (0, SHACL_js_1.literalProperty)({ path: birthDate, datatype: xsd_js_1.xsd.dateTime, maxCount: 1, }), __metadata("design:type", Date), __metadata("design:paramtypes", [Date]) ], Person.prototype, "birthDate", null); __decorate([ (0, SHACL_js_1.literalProperty)({ path: isRealPerson, datatype: xsd_js_1.xsd.boolean, maxCount: 1, }), __metadata("design:type", Boolean), __metadata("design:paramtypes", [Boolean]) ], Person.prototype, "isRealPerson", null); exports.Person = Person = Person_1 = __decorate([ package_js_1.linkedShape ], 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 models_js_1.Literal(val.toString(), xsd_js_1.xsd.integer)); } }; exports.Dog = Dog; Dog.targetClass = dogClass; __decorate([ (0, SHACL_js_1.literalProperty)({ path: guardDogLevel, maxCount: 1, datatype: xsd_js_1.xsd.integer, }), __metadata("design:type", Number), __metadata("design:paramtypes", [Number]) ], Dog.prototype, "guardDogLevel", null); exports.Dog = Dog = __decorate([ package_js_1.linkedShape ], Dog); function fromNativeDate(nativeDate) { if (!nativeDate) return null; var value = nativeDate.toISOString(); return new models_js_1.Literal(value, xsd_js_1.xsd.dateTime); } function toNativeDate(literal) { return literal ? new Date(literal instanceof TraceShape_js_1.TestNode ? null : literal.value) : null; } let p1 = Person.getFromURI(models_js_1.NamedNode.TEMP_URI_BASE + 'p1-semmy'); p1.name = 'Semmy'; p1.birthDate = new Date('1990-01-01'); p1.set(nickName, new models_js_1.Literal('Sem1')); p1.set(nickName, new models_js_1.Literal('Sem')); let p2 = Person.getFromURI(models_js_1.NamedNode.TEMP_URI_BASE + 'p2-moa'); p2.name = 'Moa'; p2.hobby = 'Jogging'; let p3 = Person.getFromURI(models_js_1.NamedNode.TEMP_URI_BASE + 'p3-jinx'); p3.name = 'Jinx'; let p4 = Person.getFromURI(models_js_1.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(models_js_1.NamedNode.TEMP_URI_BASE + 'dog1'); dog1.guardDogLevel = 2; let dog2 = Dog.getFromURI(models_js_1.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; exports.testEntities = [p1, p2, p3, p4, dog1, dog2]; exports.testProps = { name, nickName, bestFriend, hobby, hasFriend, birthDate }; exports.testTypes = { person: personClass }; (0, QueryContext_js_1.setQueryContext)('user', p3, Person); /** * * @param startPromise if provided it will be awaited before running the tests */ const runQueryTests = (startPromise = Promise.resolve()) => { (0, globals_1.describe)('query tests', () => { (0, globals_1.describe)('1. Basic Property Selection', () => { (0, globals_1.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) => { }); (0, globals_1.expect)(Array.isArray(names)).toBe(true); (0, globals_1.expect)(names.length).toBe(4); (0, globals_1.expect)(typeof names[0] === 'object').toBe(true); (0, globals_1.expect)(names[0].hasOwnProperty('name')).toBe(true); (0, globals_1.expect)(names[0].name).toBe('Semmy'); (0, globals_1.expect)(names[0].id).toBe(p1.uri); })); (0, globals_1.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]; (0, globals_1.expect)(Array.isArray(personFriends)).toBe(true); (0, globals_1.expect)(personFriends.length).toBe(4); (0, globals_1.expect)(typeof personFriends[0] === 'object').toBe(true); (0, globals_1.expect)(firstResult.hasOwnProperty('id')).toBe(true); (0, globals_1.expect)(firstResult.id).toBe(p1.uri); (0, globals_1.expect)(firstResult.friends.length).toBe(2); (0, globals_1.expect)(firstResult.friends[0].id).toBe(p2.uri); (0, globals_1.expect)(firstResult.friends[1].id).toBe(p3.uri); })); (0, globals_1.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]; (0, globals_1.expect)(Array.isArray(birthDates)).toBe(true); (0, globals_1.expect)(birthDates.length).toBe(4); (0, globals_1.expect)(typeof firstResult.birthDate === 'object').toBe(true); (0, globals_1.expect)(firstResult.birthDate.toString()).toBe(p1.birthDate.toString()); })); (0, globals_1.test)('can select a boolean', () => __awaiter(void 0, void 0, void 0, function* () { let isRealPersons = yield Person.select((p) => { return p.isRealPerson; }); (0, globals_1.expect)(Array.isArray(isRealPersons)).toBe(true); (0, globals_1.expect)(isRealPersons.length).toBe(4); (0, globals_1.expect)(isRealPersons.filter(p => p.isRealPerson !== null).length).toBe(3); let p1Result = isRealPersons.find(p => p.id === p1.uri); (0, globals_1.expect)(p1Result.isRealPerson).toBe(true); let p2Result = isRealPersons.find(p => p.id === p2.uri); (0, globals_1.expect)(p2Result.isRealPerson).toBe(false); let p4Result = isRealPersons.find(p => p.id === p4.uri); (0, globals_1.expect)(p4Result.isRealPerson).toBeNull(); })); (0, globals_1.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); (0, globals_1.expect)(qRes.name).toBe(p1.name); (0, globals_1.expect)(qRes.id).toBe(p1.uri); })); (0, globals_1.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); (0, globals_1.expect)(qRes.name).toBe(p1.name); (0, globals_1.expect)(qRes.id).toBe(p1.uri); })); (0, globals_1.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); (0, globals_1.expect)(qRes).toBeNull(); })); }); (0, globals_1.describe)('2. Nested & Path Selection', () => { (0, globals_1.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]; (0, globals_1.expect)(Array.isArray(namesOfFriends)).toBe(true); (0, globals_1.expect)(namesOfFriends.length).toBe(4); (0, globals_1.expect)(first.id).toBe(p1.uri); (0, globals_1.expect)(first.friends.length).toBe(2); (0, globals_1.expect)(first.friends[0].id).toBe(p2.uri); (0, globals_1.expect)(first.friends[0].name).toBe('Moa'); (0, globals_1.expect)(first.friends[0]['hobby']).toBeUndefined(); })); (0, globals_1.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; }); (0, globals_1.expect)(Array.isArray(friendsOfFriends)).toBe(true); let first = friendsOfFriends[0]; (0, globals_1.expect)(friendsOfFriends.length).toBe(4); (0, globals_1.expect)(first.friends.length).toBe(2); (0, globals_1.expect)(first.friends[0].friends.some((f) => f.id == p3.uri)).toBe(true); (0, globals_1.expect)(first.friends[0].friends.some((f) => f.id == p4.uri)).toBe(true); (0, globals_1.expect)(first.friends[1].friends.length).toBe(0); (0, globals_1.expect)(friendsOfFriends[3].friends.length).toBe(0); })); (0, globals_1.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; }); (0, globals_1.expect)(Array.isArray(result)).toBe(true); (0, globals_1.expect)(result.length).toBe(4); let first = result[0]; (0, globals_1.expect)(first.name).toBe('Semmy'); (0, globals_1.expect)(Array.isArray(first.friends)).toBe(true); (0, globals_1.expect)(first.friends.length).toBe(2); (0, globals_1.expect)(first.friends.some((f) => f.id === p2.uri)).toBe(true); (0, globals_1.expect)(first.friends.some((f) => f.id === p4.uri)).toBe(false); })); (0, globals_1.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" * } * ... * ] */ (0, globals_1.expect)(Array.isArray(result)).toBe(true); (0, globals_1.expect)(result.length).toBe(4); let second = result[1]; (0, globals_1.expect)(second.bestFriend.id).toBe(p3.uri); })); (0, globals_1.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; }); (0, globals_1.expect)(level3Friends.length).toBe(4); (0, globals_1.expect)(level3Friends.every((p) => p.friends.every((f) => f.friends.every((f2) => f2.friends.length === 0)))).toBe(true); })); }); (0, globals_1.describe)('3. Filtering (Where Clauses)', () => { (0, globals_1.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]; (0, globals_1.expect)(Array.isArray(friendsCalledMoa)).toBe(true); (0, globals_1.expect)(first.friends.length).toBe(1); (0, globals_1.expect)(first.friends[0].id).toBe(p2.uri); (0, globals_1.expect)(second.friends.length).toBe(0); })); (0, globals_1.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 }); }); (0, globals_1.expect)(Array.isArray(hasBestFriend)).toBe(true); (0, globals_1.expect)(hasBestFriend.length).toBe(1); (0, globals_1.expect)(hasBestFriend[0].id).toBe(p2.uri); })); (0, globals_1.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)); }); (0, globals_1.expect)(Array.isArray(hobbies)).toBe(true); (0, globals_1.expect)(hobbies.length).toBe(4); let p1Result = hobbies.find(h => h.id === p1.uri); let p2Result = hobbies.find(h => h.id === p2.uri); (0, globals_1.expect)(p1Result).toBeDefined(); (0, globals_1.expect)(p2Result).toBeDefined(); (0, globals_1.expect)(p1Result.hobby).toBeUndefined(); (0, globals_1.expect)(p2Result.hobby).toBe(p2.hobby); })); (0, globals_1.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]; (0, globals_1.expect)(Array.isArray(friendsCalledMoaThatJog)).toBe(true); (0, globals_1.expect)(first.friends.length).toBe(1); (0, globals_1.expect)(first.friends[0].id).toBe(p2.uri); (0, globals_1.expect)(second.friends.length).toBe(0); })); (0, globals_1.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]; (0, globals_1.expect)(Array.isArray(orFriends)).toBe(true); (0, globals_1.expect)(first.friends.length).toBe(2); (0, globals_1.expect)(first.friends[0].id).toBe(p2.uri); (0, globals_1.expect)(first.friends[1].id).toBe(p3.uri); (0, globals_1.expect)(second.friends.length).toBe(1); (0, globals_1.expect)(second.friends[0].id).toBe(p3.uri); })); (0, globals_1.test)('select all', () => __awaiter(void 0, void 0, void 0, function* () { let all = yield Person.select(); (0, globals_1.expect)(Array.isArray(all)).toBe(true); (0, globals_1.expect)(all.length).toBe(4); })); (0, globals_1.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); }); (0, globals_1.expect)(Array.isArray(filteredNoProps)).toBe(true); (0, globals_1.expect)(filteredNoProps.length).toBe(1); (0, globals_1.expect)(filteredNoProps[0].id).toBe(p1.uri); })); (0, globals_1.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) => { (0, globals_1.expect)(Array.isArray(result)).toBe(true); (0, globals_1.expect)(result[0].friends.length).toBe(2); (0, globals_1.expect)(result[1].friends.length).toBe(1); (0, globals_1.expect)(result[2].friends.length).toBe(0); (0, globals_1.expect)(result[3].friends.length).toBe(0); (0, globals_1.expect)(result[0].friends[0].id).toBe(p2.uri); (0, globals_1.expect)(result[0].friends[1].id).toBe(p3.uri); (0, globals_1.expect)(result[1].friends[0].id).toBe(p3.uri); }); })); (0, globals_1.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'); }); (0, globals_1.expect)(Array.isArray(peopleWithFriendsCalledMoa)).toBe(true); (0, globals_1.expect)(peopleWithFriendsCalledMoa.length).toBe(1); (0, globals_1.expect)(peopleWithFriendsCalledMoa[0].id).toBe(p1.uri); })); (0, globals_1.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'); }); }); (0, globals_1.expect)(Array.isArray(peopleWithFriendsCalledMoa)).toBe(true); (0, globals_1.expect)(peopleWithFriendsCalledMoa.length).toBe(1); (0, globals_1.expect)(peopleWithFriendsCalledMoa[0].id).toBe(p1.uri); })); (0, globals_1.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')); }); }); (0, globals_1.expect)(Array.isArray(allFriendsCalledMoaOrJinx)).toBe(true); (0, globals_1.expect)(allFriendsCalledMoaOrJinx.length).toBe(1); (0, globals_1.expect)(allFriendsCalledMoaOrJinx[0].id).toBe(p1.uri); })); (0, globals_1.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; }); (0, globals_1.expect)(Array.isArray(friendCalledJinxAndNameIsSemmy)).toBe(true); (0, globals_1.expect)(friendCalledJinxAndNameIsSemmy.length).toBe(1); (0, globals_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 (0, globals_1.expect)(Array.isArray(friendCalledJinxAndNameIsSemmy2)).toBe(true); (0, globals_1.expect)(friendCalledJinxAndNameIsSemmy2.length).toBe(2); (0, globals_1.expect)(friendCalledJinxAndNameIsSemmy2[0].id).toBe(p1.uri); (0, globals_1.expect)(friendCalledJinxAndNameIsSemmy2[1].id).toBe(p2.uri); (0, globals_1.expect)(friendCalledJinxAndNameIsSemmy2[0].name).toBe('Semmy'); (0, globals_1.expect)(typeof friendCalledJinxAndNameIsSemmy2[1].name).toBe('undefined'); })); (0, globals_1.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]; (0, globals_1.expect)(Array.isArray(friendsOfP1)).toBe(true); (0, globals_1.expect)(friendsOfP1).toHaveLength(1); (0, globals_1.expect)(first.id).toBe(p1.uri); (0, globals_1.expect)(first.friends.length).toBe(2); (0, globals_1.expect)(first.friends[0].id).toBe(p2.uri); })); (0, globals_1.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((0, QueryContext_js_1.getQueryContext)('user')); }); (0, globals_1.expect)(Array.isArray(namesHasBestFriendUser)).toBe(true); let first = namesHasBestFriendUser[0]; (0, globals_1.expect)(namesHasBestFriendUser).toHaveLength(1); (0, globals_1.expect)(first.id).toBe(p2.uri); (0, globals_1.expect)(first.name).toBe(p2.name); })); (0, globals_1.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 = (0, QueryContext_js_1.getQueryContext)('user').name; return p.friends.some(f => f.name.equals(userName)); }); (0, globals_1.expect)(Array.isArray(hasUserAsFriend)).toBe(true); (0, globals_1.expect)(hasUserAsFriend).toHaveLength(2); (0, globals_1.expect)(hasUserAsFriend.some(p => p.id === p1.uri && p.name === p1.name)).toBeTruthy(); (0, globals_1.expect)(hasUserAsFriend.some(p => p.id === p2.uri && p.name === p2.name)).toBeTruthy(); })); }); (0, globals_1.describe)('4. Aggregation & Sub-Select', () => { (0, globals_1.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 * },...] */ (0, globals_1.expect)(Array.isArray(numberOfFriends)).toBe(true); (0, globals_1.expect)(numberOfFriends[0].friends).toBe(2); (0, globals_1.expect)(numberOfFriends[1].friends).toBe(2); (0, globals_1.expect)(numberOfFriends[2].friends).toBe(0); (0, globals_1.expect)(numberOfFriends[3].friends).toBe(0); })); (0, globals_1.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 * }] * },...] */ (0, globals_1.expect)(Array.isArray(numberOfFriends)).toBe(true); (0, globals_1.expect)(Array.isArray(numberOfFriends[0].friends)).toBe(true); (0, globals_1.expect)(numberOfFriends[0].friends[0].friends).toBe(2); (0, globals_1.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); // }); (0, globals_1.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; (0, globals_1.expect)(first.hasOwnProperty('friends')).toBe(true); (0, globals_1.expect)(first.hasOwnProperty('count')).toBe(false); (0, globals_1.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); // }); (0, globals_1.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; })); (0, globals_1.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 = '' //-->