Skip to content

Commit

Permalink
Merge pull request #417 from coasys/subject-entity-pagination
Browse files Browse the repository at this point in the history
SDNA improvements
  • Loading branch information
lucksus authored Nov 21, 2023
2 parents 6d430ce + 3fda5f7 commit 7ea31b3
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 10 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

30 changes: 25 additions & 5 deletions core/src/perspectives/PerspectiveProxy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -580,12 +580,32 @@ export class PerspectiveProxy {
* If there is no such class, it gets the JS class's SDNA by calling its
* static generateSDNA() function and adds it to the perspective's SDNA.
*/
async ensureSDNASubjectClass(jsClass: any): Promise<void> {
if((await this.subjectClassesByTemplate(new jsClass)).length > 0) {
return
}
async ensureSDNASubjectClass(jsClass: any, options?: { override: boolean }): Promise<void> {
const subjectClass = await this.subjectClassesByTemplate(new jsClass)
if (!options?.override) {
if(subjectClass.length > 0) {
return
}

await this.addSdna(jsClass.generateSDNA())
} else {
let links = await this.get(new LinkQuery({
source: "ad4m://self",
predicate: "ad4m://has_zome"
}))

const link = links.find(l => {
if (l.data.target.includes(subjectClass[0])) {
return true
}

return false;
})

await this.addSdna(jsClass.generateSDNA())
await this.remove(link);

await this.addSdna(jsClass.generateSDNA())
}
}

getNeighbourhoodProxy(): NeighbourhoodProxy {
Expand Down
68 changes: 65 additions & 3 deletions core/src/subject/SubjectEntity.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Literal } from "../Literal";
import { Link } from "../links/Links";
import { PerspectiveProxy } from "../perspectives/PerspectiveProxy";
import { makeRandomPrologAtom } from "./SDNADecorators";
import { singularToPlural } from "./util";
Expand All @@ -11,13 +12,15 @@ export type QueryPartialEntity<T> = {
export class SubjectEntity {
#baseExpression: string;
#subjectClass: string;
#source: string;
#perspective: PerspectiveProxy
author: string;
timestamp: string;

constructor(perspective: PerspectiveProxy, baseExpression?: string) {
constructor(perspective: PerspectiveProxy, baseExpression?: string, source?: string) {
this.#baseExpression = baseExpression ? baseExpression : Literal.from(makeRandomPrologAtom(24)).toUrl();
this.#perspective = perspective
this.#perspective = perspective;
this.#source = source || "ad4m://self";
}

get baseExpression() {
Expand Down Expand Up @@ -95,7 +98,7 @@ export class SubjectEntity {
if (resolveLanguageResults && resolveLanguageResults.length > 0) {
resolveLanguage = resolveLanguageResults[0].Language
}

if (resolveLanguage) {
value = await this.#perspective.createExpression(value, resolveLanguage)
}
Expand Down Expand Up @@ -157,6 +160,14 @@ export class SubjectEntity {

await this.#perspective.createSubject(this, this.#baseExpression);

await this.#perspective.add(
new Link({
source: this.#source,
predicate: "ad4m://has_child",
target: this.baseExpression,
})
);

await this.update()
}

Expand Down Expand Up @@ -221,10 +232,61 @@ export class SubjectEntity {

return []
}

static async query(perspective: PerspectiveProxy, query?: SubjectEntityQueryParam) {
const source = query?.source || "ad4m://self";
let subjectClass = await perspective.stringOrTemplateObjectToSubjectClass(this)

let res = [];

if (query) {
try {
const queryResponse = (await perspective.infer(`findall([Timestamp, Base], (subject_class("${subjectClass}", C), instance(C, Base), link("${source}", Predicate, Base, Timestamp, Author)), AllData), sort(AllData, SortedData), length(SortedData, DataLength).`))[0]

if (queryResponse.DataLength >= query.size) {
const mainQuery = `findall([Timestamp, Base], (subject_class("${subjectClass}", C), instance(C, Base), link("${source}", Predicate, Base, Timestamp, Author)), AllData), sort(AllData, SortedData), reverse(SortedData, ReverseSortedData), paginate(ReverseSortedData, ${query.page}, ${query.size}, PageData).`

res = await perspective.infer(mainQuery);

res = res[0].PageData.map(r => ({
Base: r[1],
Timestamp: r[0]
}))
} else {
res = await perspective.infer(
`subject_class("${subjectClass}", C), instance(C, Base), triple("${source}", Predicate, Base).`
);
}
} catch (e) {
console.log("Query failed", e);
}
} else {
res = await perspective.infer(
`subject_class("${subjectClass}", C), instance(C, Base), triple("${source}", Predicate, Base).`
);
}

if (!res) return [];

const data = await Promise.all(
res.map(async (result) => {
const instance = new this(perspective, result.Base)

return await instance.get();
})
);

return data;
}
}

export type SubjectArray<T> = T[] | {
action: 'setter' | 'adder' | 'remover',
value: T[]
}

export type SubjectEntityQueryParam = {
source?: string;
size?: number;
page?: number;
}
2 changes: 1 addition & 1 deletion rust-executor/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ holochain_cli_bundle = { version = "0.2.2" }
holochain_types = { version = "0.2.2" }
holochain_cli_run_local_services = { version = "0.2.2" }

scryer-prolog = { version = "0.9.1", git = "https://github.com/coasys/scryer-prolog", rev = "0e90381eee2d455bf34be0209ef29996daf51c65", features = ["multi_thread"] }
scryer-prolog = { version = "0.9.1", git = "https://github.com/coasys/scryer-prolog", rev = "941a349165539aed1637e54cdc40417096424021", features = ["multi_thread"] }
# scryer-prolog = { path = "../../scryer-prolog", features = ["multi_thread"] }

[dev-dependencies]
Expand Down
10 changes: 10 additions & 0 deletions tests/js/tests/prolog-and-literals.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -671,6 +671,16 @@ describe("Prolog + Literals", () => {
expect(links![0].status).to.equal('LOCAL')
})

it("query()", async () => {
let recipes = await Recipe.query(perspective!, { page: 1, size: 2 });

expect(recipes.length).to.equal(2)

recipes = await Recipe.query(perspective!, { page: 2, size: 1 });

expect(recipes.length).to.equal(1)
})

it("delete()", async () => {
const recipe2 = await Recipe.all(perspective!);

Expand Down

0 comments on commit 7ea31b3

Please sign in to comment.