Skip to content

Commit

Permalink
fix: pagination
Browse files Browse the repository at this point in the history
  • Loading branch information
ralfaron committed Oct 21, 2024
1 parent ab5ded3 commit e774f57
Show file tree
Hide file tree
Showing 33 changed files with 488 additions and 412 deletions.
23 changes: 20 additions & 3 deletions package-lock.json

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

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
"@popperjs/core": "^2.11.8",
"@xmldom/xmldom": "^0.8.10",
"aas-core": "projects/aas-core",
"axios": "^1.7.7",
"bcryptjs": "^2.4.3",
"bootstrap": "^5.3.3",
"bootstrap-icons": "^1.11.3",
Expand Down
6 changes: 2 additions & 4 deletions projects/aas-core/src/lib/server-message.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
*
*****************************************************************************/

import { AASContainer, AASDocument, AASEndpoint } from './types.js';
import { AASDocument, AASEndpoint } from './types.js';

/** Defines the message types. */
export type AASServerMessageType =
Expand All @@ -22,9 +22,7 @@ export type AASServerMessageType =
export interface AASServerMessage {
/** The type of change. */
type: AASServerMessageType;
/** The container if type `ContainerAdded` and `ContainerRemoved`. */
container?: AASContainer;
/** The endpoint if type `ContainerAdded`, `ContainerRemoved`, `EndpointAdded`, `EndpointRemoved`. */
/** The endpoint if type `EndpointAdded`, `EndpointRemoved`. */
endpoint?: AASEndpoint;
/** The document if type `Added`, `Removed` or `Changed` */
document?: AASDocument;
Expand Down
1 change: 1 addition & 0 deletions projects/aas-core/src/lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ export type AASEndpoint = {

/** Represents a server (AASX, OPC-UA) or file directory (AASX package files). */
export interface AASContainer extends AASEndpoint {
cursor?: string;
documents?: AASDocument[];
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ describe('AddEndpointFormComponent', () => {
let endpoint: AASEndpoint | undefined;
spyOn(modal, 'close').and.callFake(result => (endpoint = result));

component.item.set({ ...component.items()[3], value: 'file:///my-endpoint' });
component.selectItem(component.items()[3]);
component.name.set('My endpoint');

form.dispatchEvent(new Event('submit'));
Expand All @@ -65,7 +65,7 @@ describe('AddEndpointFormComponent', () => {
let endpoint: AASEndpoint | undefined;
spyOn(modal, 'close').and.callFake(result => (endpoint = result));

component.item.set({ ...component.items()[3], value: 'file:///a\\b\\my-endpoint' });
component.selectItem(component.items()[3]);
component.name.set('My endpoint');

form.dispatchEvent(new Event('submit'));
Expand All @@ -78,7 +78,7 @@ describe('AddEndpointFormComponent', () => {
it('ignores AAS endpoint: Name: "", URL: "file:///my-endpoint"', () => {
spyOn(modal, 'close');

component.item.set({ ...component.items()[3], value: 'file:///my-endpoint' });
component.selectItem(component.items()[3]);
component.name.set('');

form.dispatchEvent(new Event('submit'));
Expand All @@ -89,7 +89,7 @@ describe('AddEndpointFormComponent', () => {
it('ignores AAS endpoint Name: "My endpoint", URL: "file:///"', () => {
spyOn(modal, 'close');

component.item.set({ ...component.items()[3], value: 'file:///' });
component.selectItem(component.items()[3]);
component.name.set('My endpoint');

form.dispatchEvent(new Event('submit'));
Expand All @@ -101,7 +101,7 @@ describe('AddEndpointFormComponent', () => {
let endpoint: AASEndpoint | undefined;
spyOn(modal, 'close').and.callFake(result => (endpoint = result));

component.item.set({ ...component.items()[1], value: 'opc.tcp://localhost:30001/I4AASServer' });
component.selectItem(component.items()[1]);
component.name.set('I4AAS Server');

form.dispatchEvent(new Event('submit'));
Expand All @@ -114,7 +114,7 @@ describe('AddEndpointFormComponent', () => {
it('ignores AAS endpoint Name: "I4AAS Server", URL: "opc.tcp://"', () => {
spyOn(modal, 'close');

component.item.set(component.items()[1]);
component.selectItem(component.items()[1]);
fixture.detectChanges();

inputNameElement.value = 'I4AAS Server';
Expand All @@ -131,7 +131,7 @@ describe('AddEndpointFormComponent', () => {
let endpoint: AASEndpoint | undefined;
spyOn(modal, 'close').and.callFake(result => (endpoint = result));

component.item.set({ ...component.items()[0], value: 'http://localhost:50001/' });
component.selectItem(component.items()[0]);
component.name.set('AASX Server');

form.dispatchEvent(new Event('submit'));
Expand All @@ -145,7 +145,7 @@ describe('AddEndpointFormComponent', () => {
let endpoint: AASEndpoint | undefined;
spyOn(modal, 'close').and.callFake(result => (endpoint = result));

component.item.set({ ...component.items()[2], value: 'http://localhost:8080/root/folder' });
component.selectItem(component.items()[2]);
component.name.set('WebDAV Server');

form.dispatchEvent(new Event('submit'));
Expand Down
1 change: 1 addition & 0 deletions projects/aas-server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"dependencies": {
"@babel/polyfill": "^7.4.4",
"@xmldom/xmldom": "^0.8.10",
"axios": "^1.7.7",
"bcryptjs": "^2.4.3",
"chalk": "^2.4.1",
"cors": "^2.8.5",
Expand Down
8 changes: 7 additions & 1 deletion projects/aas-server/src/app/aas-index/aas-index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import {
toBoolean,
} from 'aas-core';

import { PagedResult } from '../types/paged-result.js';

export abstract class AASIndex {
public abstract getCount(query?: string): Promise<number>;

Expand All @@ -35,7 +37,11 @@ export abstract class AASIndex {

public abstract getDocuments(cursor: AASCursor, query?: string, language?: string): Promise<AASPage>;

public abstract getContainerDocuments(endpointName: string): Promise<AASDocument[]>;
public abstract nextPage(
endpointName: string,
cursor: string | undefined,
limit?: number,
): Promise<PagedResult<AASDocument>>;

public abstract update(document: AASDocument): Promise<void>;

Expand Down
48 changes: 46 additions & 2 deletions projects/aas-server/src/app/aas-index/lowdb/lowdb-index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ import { Variable } from '../../variable.js';
import { urlToEndpoint } from '../../configuration.js';
import { ERRORS } from '../../errors.js';
import { LowDbData, LowDbDocument, LowDbElement } from './lowdb-types.js';
import { decodeBase64Url, encodeBase64Url } from '../../convert.js';
import { PagedResult } from '../../types/paged-result.js';

export class LowDbIndex extends AASIndex {
private readonly promise: Promise<void>;
Expand Down Expand Up @@ -88,9 +90,51 @@ export class LowDbIndex extends AASIndex {
return true;
}

public override async getContainerDocuments(endpointName: string): Promise<AASDocument[]> {
public override async nextPage(
endpointName: string,
cursor: string | undefined,
limit: number = 10,
): Promise<PagedResult<AASDocument>> {
await this.promise;
return this.db.data.documents.filter(document => document.endpoint === endpointName);

if (cursor) {
cursor = decodeBase64Url(cursor);
}

const documents: AASDocument[] = [];
if (this.db.data.documents.length === 0) {
return { result: documents, paging_metadata: {} };
}

const items = this.db.data.documents;
const index = items.findIndex(item => {
if (item.endpoint !== endpointName) {
return false;
}

return cursor === undefined || cursor.localeCompare(item.id) <= 0;
});

if (index < 0) {
return { result: documents, paging_metadata: {} };
}

const result: AASDocument[] = [];
for (let i = 0, j = index, n = items.length; i < limit && j < n; i++, j++) {
const item = items[j];
if (item.endpoint !== endpointName) {
break;
}

result.push(item);
}

const k = index + limit + 1;
if (k >= items.length || items[k].endpoint !== endpointName) {
return { result, paging_metadata: {} };
}

return { result, paging_metadata: { cursor: encodeBase64Url(items[k].id) } };
}

public override async getDocuments(cursor: AASCursor, query?: string, language?: string): Promise<AASPage> {
Expand Down
31 changes: 25 additions & 6 deletions projects/aas-server/src/app/aas-index/mysql/mysql-index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import { Variable } from '../../variable.js';
import { urlToEndpoint } from '../../configuration.js';
import { MySqlQuery } from './mysql-query.js';
import { DocumentCount, MySqlDocument, MySqlEndpoint } from './mysql-types.js';
import { PagedResult } from '../../types/paged-result.js';
import { encodeBase64Url } from '../../convert.js';

export class MySqlIndex extends AASIndex {
private readonly connection: Promise<Connection>;
Expand Down Expand Up @@ -117,12 +119,29 @@ export class MySqlIndex extends AASIndex {
return this.getLastPage(cursor.limit);
}

public override async getContainerDocuments(endpointName: string): Promise<AASDocument[]> {
return (
await (
await this.connection
).query<MySqlDocument[]>('SELECT * FROM `documents` WHERE endpoint = ?', [endpointName])
)[0].map(row => this.toDocument(row));
public override async nextPage(
endpointName: string,
cursor: string | undefined,
limit: number = 100,
): Promise<PagedResult<AASDocument>> {
const connection = await this.connection;
let sql: string;
const values: unknown[] = [endpointName + cursor];
if (cursor) {
values.push(limit + 1);
sql = 'SELECT * FROM `documents` WHERE CONCAT(endpoint, id) > ? ORDER BY endpoint ASC, id ASC LIMIT ?;';
} else {
sql = 'SELECT * FROM `documents` ORDER BY endpoint ASC, id ASC LIMIT ?;';
}

const [results] = await connection.query<MySqlDocument[]>(sql, values);
const documents = results.map(result => this.toDocument(result));
return {
result: documents.slice(0, limit),
paging_metadata: {
cursor: documents.length >= limit + 1 ? encodeBase64Url(documents[limit].id) : undefined,
},
};
}

public override async update(document: AASDocument): Promise<void> {
Expand Down
Loading

0 comments on commit e774f57

Please sign in to comment.