2019-06-20 00:20:09 +02:00
|
|
|
import { URL } from 'whatwg-url'
|
|
|
|
import { DDO } from '../ddo/DDO'
|
|
|
|
import DID from '../ocean/DID'
|
2020-03-30 13:56:57 +02:00
|
|
|
import { EditableMetaData } from '../ddo/MetaData'
|
2020-01-15 10:33:42 +01:00
|
|
|
import { Logger } from '../utils'
|
|
|
|
import { WebServiceConnector } from '../ocean/utils/WebServiceConnector'
|
2020-03-30 14:03:32 +02:00
|
|
|
|
2019-06-20 00:20:09 +02:00
|
|
|
const apiPath = '/api/v1/aquarius/assets/ddo'
|
2018-11-21 16:47:24 +01:00
|
|
|
|
2019-04-05 12:20:42 +02:00
|
|
|
export interface QueryResult {
|
|
|
|
results: DDO[]
|
|
|
|
page: number
|
|
|
|
totalPages: number
|
|
|
|
totalResults: number
|
|
|
|
}
|
|
|
|
|
2019-04-01 12:40:45 +02:00
|
|
|
export interface SearchQuery {
|
|
|
|
text?: string
|
2019-05-07 13:08:26 +02:00
|
|
|
offset?: number
|
|
|
|
page?: number
|
2019-06-20 00:20:09 +02:00
|
|
|
query: { [property: string]: string | number | string[] | number[] }
|
|
|
|
sort?: { [jsonPath: string]: number }
|
2019-04-01 12:40:45 +02:00
|
|
|
}
|
|
|
|
|
2019-01-09 16:15:32 +01:00
|
|
|
/**
|
2020-01-15 15:24:32 +01:00
|
|
|
* Provides an interface with Aquarius.
|
2019-01-09 16:15:32 +01:00
|
|
|
* Aquarius provides an off-chain database store for metadata about data assets.
|
|
|
|
*/
|
2020-01-15 10:33:42 +01:00
|
|
|
export class Aquarius {
|
2020-01-15 11:42:52 +01:00
|
|
|
public fetch: WebServiceConnector
|
2020-01-15 10:33:42 +01:00
|
|
|
private logger: Logger
|
|
|
|
private aquariusUri: string
|
|
|
|
|
2019-03-21 02:56:58 +01:00
|
|
|
private get url() {
|
2020-01-15 10:33:42 +01:00
|
|
|
return this.aquariusUri
|
2019-03-21 02:56:58 +01:00
|
|
|
}
|
2018-10-26 10:40:46 +02:00
|
|
|
|
2020-01-15 15:24:32 +01:00
|
|
|
/**
|
|
|
|
* Instantiate Aquarius (independently of Ocean) for off-chain interaction.
|
|
|
|
* @param {String} aquariusUri
|
|
|
|
* @param {Logger} logger
|
|
|
|
*/
|
|
|
|
constructor(aquariusUri: string, logger: Logger) {
|
2020-01-15 10:33:42 +01:00
|
|
|
this.fetch = new WebServiceConnector(logger)
|
|
|
|
this.logger = logger
|
|
|
|
this.aquariusUri = aquariusUri
|
2018-10-26 10:40:46 +02:00
|
|
|
}
|
|
|
|
|
2019-06-14 12:07:35 +02:00
|
|
|
public async getVersionInfo() {
|
2020-01-15 10:33:42 +01:00
|
|
|
return (await this.fetch.get(this.url)).json()
|
2019-06-14 00:34:53 +02:00
|
|
|
}
|
|
|
|
|
2018-11-01 13:24:41 +01:00
|
|
|
public async getAccessUrl(accessToken: any, payload: any): Promise<string> {
|
2020-01-15 10:33:42 +01:00
|
|
|
const accessUrl: string = await this.fetch
|
2019-09-09 12:18:54 +02:00
|
|
|
.post(`${accessToken.service_endpoint}/${accessToken.resource_id}`, payload)
|
2018-11-01 13:24:41 +01:00
|
|
|
.then((response: any): string => {
|
2018-10-17 18:24:01 +02:00
|
|
|
if (response.ok) {
|
|
|
|
return response.text()
|
|
|
|
}
|
2019-09-09 12:18:54 +02:00
|
|
|
this.logger.error('Failed: ', response.status, response.statusText)
|
2018-11-07 14:33:56 +01:00
|
|
|
return null
|
2018-10-17 18:24:01 +02:00
|
|
|
})
|
2018-11-01 13:24:41 +01:00
|
|
|
.then((consumptionUrl: string): string => {
|
2019-09-09 12:18:54 +02:00
|
|
|
this.logger.error('Success accessing consume endpoint: ', consumptionUrl)
|
2018-10-17 18:24:01 +02:00
|
|
|
return consumptionUrl
|
|
|
|
})
|
2020-05-19 16:15:56 +02:00
|
|
|
.catch((error) => {
|
2019-11-15 00:00:10 +01:00
|
|
|
this.logger.error(
|
|
|
|
'Error fetching the data asset consumption url: ',
|
|
|
|
error
|
|
|
|
)
|
2018-11-01 13:24:41 +01:00
|
|
|
return null
|
2018-10-17 18:24:01 +02:00
|
|
|
})
|
|
|
|
|
|
|
|
return accessUrl
|
|
|
|
}
|
2018-10-26 10:40:46 +02:00
|
|
|
|
2019-01-09 16:15:32 +01:00
|
|
|
/**
|
|
|
|
* Search over the DDOs using a query.
|
|
|
|
* @param {SearchQuery} query Query to filter the DDOs.
|
2019-04-05 12:20:42 +02:00
|
|
|
* @return {Promise<QueryResult>}
|
2019-01-09 16:15:32 +01:00
|
|
|
*/
|
2019-04-05 12:20:42 +02:00
|
|
|
public async queryMetadata(query: SearchQuery): Promise<QueryResult> {
|
2020-01-15 10:33:42 +01:00
|
|
|
const result: QueryResult = await this.fetch
|
2018-11-21 16:47:24 +01:00
|
|
|
.post(`${this.url}${apiPath}/query`, JSON.stringify(query))
|
2018-10-26 10:40:46 +02:00
|
|
|
.then((response: any) => {
|
|
|
|
if (response.ok) {
|
2018-11-16 11:35:28 +01:00
|
|
|
return response.json() as DDO[]
|
2018-10-26 10:40:46 +02:00
|
|
|
}
|
2019-11-15 00:00:10 +01:00
|
|
|
this.logger.error(
|
|
|
|
'queryMetadata failed:',
|
|
|
|
response.status,
|
|
|
|
response.statusText
|
|
|
|
)
|
2019-04-05 12:20:42 +02:00
|
|
|
return this.transformResult()
|
2018-11-12 08:33:19 +01:00
|
|
|
})
|
2020-05-19 16:15:56 +02:00
|
|
|
.then((results) => {
|
2019-04-05 12:20:42 +02:00
|
|
|
return this.transformResult(results)
|
2018-10-26 10:40:46 +02:00
|
|
|
})
|
2020-05-19 16:15:56 +02:00
|
|
|
.catch((error) => {
|
2019-06-20 00:20:09 +02:00
|
|
|
this.logger.error('Error fetching querying metadata: ', error)
|
2019-04-05 12:20:42 +02:00
|
|
|
return this.transformResult()
|
2018-10-29 16:38:23 +01:00
|
|
|
})
|
|
|
|
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
2019-01-09 16:15:32 +01:00
|
|
|
/**
|
|
|
|
* Search over the DDOs using a query.
|
|
|
|
* @param {SearchQuery} query Query to filter the DDOs.
|
2019-04-05 12:20:42 +02:00
|
|
|
* @return {Promise<QueryResult>}
|
2019-01-09 16:15:32 +01:00
|
|
|
*/
|
2019-04-05 12:20:42 +02:00
|
|
|
public async queryMetadataByText(query: SearchQuery): Promise<QueryResult> {
|
2018-11-21 16:47:24 +01:00
|
|
|
const fullUrl = new URL(`${this.url}${apiPath}/query`)
|
2019-06-20 00:20:09 +02:00
|
|
|
fullUrl.searchParams.append('text', query.text)
|
2019-11-15 00:00:10 +01:00
|
|
|
fullUrl.searchParams.append(
|
|
|
|
'sort',
|
|
|
|
decodeURIComponent(JSON.stringify(query.sort))
|
|
|
|
)
|
2019-06-20 00:20:09 +02:00
|
|
|
fullUrl.searchParams.append('offset', query.offset.toString())
|
|
|
|
fullUrl.searchParams.append('page', query.page.toString())
|
2020-01-15 10:33:42 +01:00
|
|
|
|
|
|
|
const result: QueryResult = await this.fetch
|
2018-11-01 12:47:48 +01:00
|
|
|
.get(fullUrl)
|
2018-10-29 16:38:23 +01:00
|
|
|
.then((response: any) => {
|
|
|
|
if (response.ok) {
|
2018-11-16 11:35:28 +01:00
|
|
|
return response.json() as DDO[]
|
2018-10-29 16:38:23 +01:00
|
|
|
}
|
2019-11-15 00:00:10 +01:00
|
|
|
this.logger.log(
|
|
|
|
'queryMetadataByText failed:',
|
|
|
|
response.status,
|
|
|
|
response.statusText
|
|
|
|
)
|
2019-04-05 12:20:42 +02:00
|
|
|
return this.transformResult()
|
2018-11-12 08:33:19 +01:00
|
|
|
})
|
2020-05-19 16:15:56 +02:00
|
|
|
.then((results) => {
|
2019-04-05 12:20:42 +02:00
|
|
|
return this.transformResult(results)
|
2018-10-29 16:38:23 +01:00
|
|
|
})
|
2020-05-19 16:15:56 +02:00
|
|
|
.catch((error) => {
|
2019-09-09 12:18:54 +02:00
|
|
|
this.logger.error('Error fetching querying metadata by text: ', error)
|
2019-04-05 12:20:42 +02:00
|
|
|
return this.transformResult()
|
2018-10-26 10:40:46 +02:00
|
|
|
})
|
|
|
|
|
|
|
|
return result
|
|
|
|
}
|
2018-11-01 12:47:48 +01:00
|
|
|
|
2019-01-09 16:15:32 +01:00
|
|
|
/**
|
|
|
|
* Stores a DDO in Aquarius.
|
|
|
|
* @param {DDO} ddo DDO to be stored.
|
|
|
|
* @return {Promise<DDO>} Final DDO.
|
|
|
|
*/
|
2018-11-01 12:47:48 +01:00
|
|
|
public async storeDDO(ddo: DDO): Promise<DDO> {
|
2018-11-21 16:47:24 +01:00
|
|
|
const fullUrl = `${this.url}${apiPath}`
|
2020-01-15 10:33:42 +01:00
|
|
|
const result: DDO = await this.fetch
|
2018-11-01 12:47:48 +01:00
|
|
|
.post(fullUrl, DDO.serialize(ddo))
|
|
|
|
.then((response: any) => {
|
|
|
|
if (response.ok) {
|
2018-11-16 13:34:52 +01:00
|
|
|
return response.json()
|
2018-11-01 12:47:48 +01:00
|
|
|
}
|
2019-11-15 00:00:10 +01:00
|
|
|
this.logger.error(
|
|
|
|
'storeDDO failed:',
|
|
|
|
response.status,
|
|
|
|
response.statusText,
|
|
|
|
ddo
|
|
|
|
)
|
2018-11-16 11:35:28 +01:00
|
|
|
return null as DDO
|
2018-11-01 12:47:48 +01:00
|
|
|
})
|
2018-11-16 13:34:52 +01:00
|
|
|
.then((response: DDO) => {
|
|
|
|
return new DDO(response) as DDO
|
|
|
|
})
|
2020-05-19 16:15:56 +02:00
|
|
|
.catch((error) => {
|
2019-06-20 00:20:09 +02:00
|
|
|
this.logger.error('Error fetching querying metadata: ', error)
|
2018-11-16 11:35:28 +01:00
|
|
|
return null as DDO
|
2018-11-01 12:47:48 +01:00
|
|
|
})
|
|
|
|
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
2019-01-09 16:15:32 +01:00
|
|
|
/**
|
|
|
|
* Retrieves a DDO by DID.
|
2019-07-16 14:56:56 +02:00
|
|
|
* @param {DID | string} did DID of the asset.
|
2019-01-09 16:15:32 +01:00
|
|
|
* @return {Promise<DDO>} DDO of the asset.
|
|
|
|
*/
|
2019-11-15 00:00:10 +01:00
|
|
|
public async retrieveDDO(
|
|
|
|
did: DID | string,
|
|
|
|
metadataServiceEndpoint?: string
|
|
|
|
): Promise<DDO> {
|
2019-07-16 14:56:56 +02:00
|
|
|
did = did && DID.parse(did)
|
2019-09-09 12:18:54 +02:00
|
|
|
const fullUrl = metadataServiceEndpoint || `${this.url}${apiPath}/${did.getDid()}`
|
2020-01-15 10:33:42 +01:00
|
|
|
const result = await this.fetch
|
2018-11-01 12:47:48 +01:00
|
|
|
.get(fullUrl)
|
|
|
|
.then((response: any) => {
|
|
|
|
if (response.ok) {
|
2018-11-16 13:34:52 +01:00
|
|
|
return response.json()
|
2018-11-01 12:47:48 +01:00
|
|
|
}
|
2019-11-15 00:00:10 +01:00
|
|
|
this.logger.log(
|
|
|
|
'retrieveDDO failed:',
|
|
|
|
response.status,
|
|
|
|
response.statusText,
|
|
|
|
did
|
|
|
|
)
|
2018-11-16 11:35:28 +01:00
|
|
|
return null as DDO
|
2018-11-01 12:47:48 +01:00
|
|
|
})
|
2018-11-16 13:34:52 +01:00
|
|
|
.then((response: DDO) => {
|
|
|
|
return new DDO(response) as DDO
|
|
|
|
})
|
2020-05-19 16:15:56 +02:00
|
|
|
.catch((error) => {
|
2019-06-20 00:20:09 +02:00
|
|
|
this.logger.error('Error fetching querying metadata: ', error)
|
2018-11-16 11:35:28 +01:00
|
|
|
return null as DDO
|
2018-11-01 12:47:48 +01:00
|
|
|
})
|
|
|
|
|
|
|
|
return result
|
|
|
|
}
|
2018-11-07 14:33:56 +01:00
|
|
|
|
2019-07-16 14:56:56 +02:00
|
|
|
public async retrieveDDOByUrl(metadataServiceEndpoint?: string) {
|
|
|
|
return this.retrieveDDO(undefined, metadataServiceEndpoint)
|
|
|
|
}
|
|
|
|
|
2020-02-11 21:11:37 +01:00
|
|
|
/**
|
|
|
|
* Transfer ownership of a DDO
|
|
|
|
* @param {DID | string} did DID of the asset to update.
|
|
|
|
* @param {String} newOwner New owner of the DDO
|
|
|
|
* @param {String} updated Updated field of the DDO
|
|
|
|
* @param {String} signature Signature using updated field to verify that the consumer has rights
|
|
|
|
* @return {Promise<String>} Result.
|
|
|
|
*/
|
2020-02-11 21:15:42 +01:00
|
|
|
public async transferOwnership(
|
|
|
|
did: DID | string,
|
|
|
|
newOwner: string,
|
|
|
|
updated: string,
|
|
|
|
signature: string
|
|
|
|
): Promise<string> {
|
2020-02-11 21:11:37 +01:00
|
|
|
did = did && DID.parse(did)
|
2020-03-25 19:18:07 +01:00
|
|
|
const fullUrl = `${this.url}${apiPath}/owner/update/${did.getDid()}`
|
2020-02-11 21:11:37 +01:00
|
|
|
const result = await this.fetch
|
2020-02-11 21:15:42 +01:00
|
|
|
.put(
|
|
|
|
fullUrl,
|
|
|
|
JSON.stringify({
|
|
|
|
signature: signature,
|
|
|
|
updated: updated,
|
2020-03-25 10:21:03 +01:00
|
|
|
newOwner: newOwner
|
2020-02-11 21:15:42 +01:00
|
|
|
})
|
|
|
|
)
|
2020-02-11 21:11:37 +01:00
|
|
|
.then((response: any) => {
|
|
|
|
if (response.ok) {
|
|
|
|
return response.text
|
|
|
|
}
|
|
|
|
this.logger.log(
|
|
|
|
'transferownership failed:',
|
|
|
|
response.status,
|
|
|
|
response.statusText
|
|
|
|
)
|
2020-02-11 21:15:42 +01:00
|
|
|
return null
|
2020-02-11 21:11:37 +01:00
|
|
|
})
|
2020-02-11 21:15:42 +01:00
|
|
|
|
2020-05-19 16:15:56 +02:00
|
|
|
.catch((error) => {
|
2020-03-25 10:21:03 +01:00
|
|
|
this.logger.error('Error transfering ownership metadata: ', error)
|
2020-02-11 21:11:37 +01:00
|
|
|
return null
|
|
|
|
})
|
|
|
|
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
2020-05-09 21:20:40 +02:00
|
|
|
/**
|
|
|
|
* Update Compute Privacy
|
2020-05-09 21:14:57 +02:00
|
|
|
* @param {DID | string} did DID of the asset to update.
|
|
|
|
* @param {number } serviceIndex Service index
|
|
|
|
* @param {boolean} allowRawAlgorithm Allow Raw Algorithms
|
|
|
|
* @param {boolean} allowNetworkAccess Allow Raw Algorithms
|
|
|
|
* @param {String[]} trustedAlgorithms Allow Raw Algorithms
|
|
|
|
* @param {String} updated Updated field of the DDO
|
|
|
|
* @param {String} signature Signature using updated field to verify that the consumer has rights
|
|
|
|
* @return {Promise<String>} Result.
|
|
|
|
*/
|
|
|
|
public async updateComputePrivacy(
|
|
|
|
did: DID | string,
|
|
|
|
serviceIndex: number,
|
|
|
|
allowRawAlgorithm: boolean,
|
|
|
|
allowNetworkAccess: boolean,
|
|
|
|
trustedAlgorithms: string[],
|
|
|
|
updated: string,
|
|
|
|
signature: string
|
|
|
|
): Promise<string> {
|
|
|
|
did = did && DID.parse(did)
|
|
|
|
const fullUrl = `${this.url}${apiPath}/computePrivacy/update/${did.getDid()}`
|
|
|
|
const result = await this.fetch
|
|
|
|
.put(
|
|
|
|
fullUrl,
|
|
|
|
JSON.stringify({
|
|
|
|
signature: signature,
|
|
|
|
updated: updated,
|
|
|
|
serviceIndex: serviceIndex,
|
|
|
|
allowRawAlgorithm: allowRawAlgorithm,
|
|
|
|
allowNetworkAccess: allowNetworkAccess,
|
|
|
|
trustedAlgorithms: trustedAlgorithms
|
|
|
|
})
|
|
|
|
)
|
|
|
|
.then((response: any) => {
|
|
|
|
if (response.ok) {
|
|
|
|
return response.text
|
|
|
|
}
|
|
|
|
this.logger.log(
|
|
|
|
'update compute privacy failed:',
|
|
|
|
response.status,
|
|
|
|
response.statusText
|
|
|
|
)
|
|
|
|
return null
|
|
|
|
})
|
|
|
|
|
2020-05-19 16:15:56 +02:00
|
|
|
.catch((error) => {
|
2020-05-09 21:14:57 +02:00
|
|
|
this.logger.error('Error updating compute privacy: ', error)
|
|
|
|
return null
|
|
|
|
})
|
|
|
|
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
2020-03-31 11:01:00 +02:00
|
|
|
/**
|
|
|
|
* Edit Metadata for a DDO.
|
|
|
|
* @param {did} string DID.
|
|
|
|
* @param {newMetadata} EditableMetaData Metadata fields & new values.
|
|
|
|
* @param {String} updated Updated field of the DDO
|
|
|
|
* @param {String} signature Signature using updated field to verify that the consumer has rights
|
|
|
|
* @return {Promise<String>} Result.
|
|
|
|
*/
|
2020-03-30 13:56:57 +02:00
|
|
|
public async editMetadata(
|
|
|
|
did: DID | string,
|
|
|
|
newMetadata: EditableMetaData,
|
|
|
|
updated: string,
|
|
|
|
signature: string
|
|
|
|
): Promise<string> {
|
|
|
|
did = did && DID.parse(did)
|
2020-04-08 15:49:22 +02:00
|
|
|
const fullUrl = `${this.url}${apiPath}/metadata/${did.getDid()}`
|
2020-03-30 14:09:23 +02:00
|
|
|
const data = Object()
|
|
|
|
if (newMetadata.description != null) data.description = newMetadata.description
|
|
|
|
if (newMetadata.title != null) data.title = newMetadata.title
|
2020-03-30 13:56:57 +02:00
|
|
|
if (newMetadata.servicePrices != null)
|
|
|
|
data.servicePrices = newMetadata.servicePrices
|
2020-03-30 16:53:36 +02:00
|
|
|
if (newMetadata.links != null) data.links = newMetadata.links
|
2020-03-30 13:56:57 +02:00
|
|
|
data.updated = updated
|
|
|
|
data.signature = signature
|
|
|
|
const result = await this.fetch
|
2020-03-30 14:09:23 +02:00
|
|
|
.put(fullUrl, JSON.stringify(data))
|
2020-03-30 13:56:57 +02:00
|
|
|
.then((response: any) => {
|
|
|
|
if (response.ok) {
|
|
|
|
return response.text
|
|
|
|
}
|
|
|
|
this.logger.log(
|
2020-03-30 16:53:36 +02:00
|
|
|
'editMetaData failed:',
|
2020-03-30 13:56:57 +02:00
|
|
|
response.status,
|
|
|
|
response.statusText
|
|
|
|
)
|
|
|
|
return null
|
|
|
|
})
|
|
|
|
|
2020-05-19 16:15:56 +02:00
|
|
|
.catch((error) => {
|
2020-03-30 13:56:57 +02:00
|
|
|
this.logger.error('Error transfering ownership metadata: ', error)
|
|
|
|
return null
|
|
|
|
})
|
|
|
|
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
2020-03-31 11:01:00 +02:00
|
|
|
/**
|
|
|
|
* Retire a DDO (Delete)
|
|
|
|
* @param {DID | string} did DID of the asset to update.
|
|
|
|
* @param {String} updated Updated field of the DDO
|
|
|
|
* @param {String} signature Signature using updated field to verify that the consumer has rights
|
|
|
|
* @return {Promise<String>} Result.
|
|
|
|
*/
|
2020-03-30 13:56:57 +02:00
|
|
|
public async retire(
|
|
|
|
did: DID | string,
|
|
|
|
updated: string,
|
|
|
|
signature: string
|
|
|
|
): Promise<string> {
|
|
|
|
did = did && DID.parse(did)
|
|
|
|
const fullUrl = `${this.url}${apiPath}/${did.getDid()}`
|
|
|
|
const result = await this.fetch
|
|
|
|
.delete(
|
|
|
|
fullUrl,
|
|
|
|
JSON.stringify({
|
|
|
|
signature: signature,
|
|
|
|
updated: updated
|
|
|
|
})
|
|
|
|
)
|
|
|
|
.then((response: any) => {
|
|
|
|
if (response.ok) {
|
|
|
|
return response.text
|
|
|
|
}
|
2020-03-30 16:53:36 +02:00
|
|
|
this.logger.log('retire failed:', response.status, response.statusText)
|
2020-03-30 13:56:57 +02:00
|
|
|
return null
|
|
|
|
})
|
|
|
|
|
2020-05-19 16:15:56 +02:00
|
|
|
.catch((error) => {
|
2020-03-30 13:56:57 +02:00
|
|
|
this.logger.error('Error transfering ownership metadata: ', error)
|
|
|
|
return null
|
|
|
|
})
|
|
|
|
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
2018-12-17 15:54:58 +01:00
|
|
|
public getServiceEndpoint(did: DID) {
|
2019-04-29 13:31:03 +02:00
|
|
|
return `${this.url}/api/v1/aquarius/assets/ddo/did:op:${did.getId()}`
|
2018-11-07 14:33:56 +01:00
|
|
|
}
|
2019-04-05 12:20:42 +02:00
|
|
|
|
|
|
|
private transformResult(
|
2019-09-09 12:18:54 +02:00
|
|
|
{ results, page, total_pages: totalPages, total_results: totalResults }: any = {
|
2019-06-20 00:20:09 +02:00
|
|
|
result: [],
|
|
|
|
page: 0,
|
2019-06-24 13:06:38 +02:00
|
|
|
total_pages: 0, // eslint-disable-line @typescript-eslint/camelcase
|
|
|
|
total_results: 0 // eslint-disable-line @typescript-eslint/camelcase
|
2019-06-20 00:20:09 +02:00
|
|
|
}
|
2019-04-05 12:20:42 +02:00
|
|
|
): QueryResult {
|
|
|
|
return {
|
2020-05-19 16:15:56 +02:00
|
|
|
results: (results || []).map((ddo) => new DDO(ddo as DDO)),
|
2019-04-05 12:20:42 +02:00
|
|
|
page,
|
2019-06-24 13:06:38 +02:00
|
|
|
totalPages,
|
|
|
|
totalResults
|
2019-04-05 12:20:42 +02:00
|
|
|
}
|
|
|
|
}
|
2018-10-17 18:24:01 +02:00
|
|
|
}
|