Skip to content

Commit

Permalink
WIP: Move API calls and params/response types to client.ts
Browse files Browse the repository at this point in the history
  • Loading branch information
arildm committed Oct 23, 2024
1 parent 1f600ac commit d44de2b
Show file tree
Hide file tree
Showing 12 changed files with 223 additions and 191 deletions.
39 changes: 10 additions & 29 deletions app/scripts/backend/backend.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,9 @@ import { KorpResponse, WithinParameters } from "@/backend/types"
import { SavedSearch } from "@/local-storage"
import settings from "@/settings"
import { httpConfAddMethodFetch } from "@/util"
import { KorpStatsResponse, normalizeStatsData } from "@/backend/stats-proxy"
import { normalizeStatsData } from "@/backend/stats-proxy"
import { MapResult, parseMapData } from "@/map_services"
import { KorpQueryResponse } from "@/backend/kwic-proxy"

type KorpLoglikeResponse = {
/** Log-likelihood average. */
average: number
/** Log-likelihood values. */
loglike: Record<string, number>
/** Absolute frequency for the values in set 1. */
set1: Record<string, number>
/** Absolute frequency for the values in set 2. */
set2: Record<string, number>
}
import { count, loglike, QueryResponse } from "./client"

export type CompareResult = [CompareTables, number, SavedSearch, SavedSearch, string[]]

Expand Down Expand Up @@ -80,7 +69,7 @@ export async function requestCompare(
const rankedReduce = _.filter(reduce, (item) => cl.getCurrentAttributes(cl.getReduceLang())[item]?.ranked)
const top = rankedReduce.map((item) => item + ":1").join(",")

const params = {
const data = await loglike({
group_by: reduce.join(","),
set1_corpus: corpora1.join(",").toUpperCase(),
set1_cqp: cmpObj1.cqp,
Expand All @@ -89,9 +78,7 @@ export async function requestCompare(
max: "50",
split,
top,
}

const data = await korpRequest<KorpLoglikeResponse>("loglike", params)
})

if ("ERROR" in data) {
// TODO Create a KorpBackendError which could be displayed nicely
Expand Down Expand Up @@ -137,19 +124,16 @@ export async function requestMapData(
const cqpSubExprs = {}
_.map(_.keys(cqpExprs), (subCqp, idx) => (cqpSubExprs[`subcqp${idx}`] = subCqp))

const params = {
const data = await count({
group_by_struct: attribute.label,
cqp,
corpus: attribute.corpora.join(","),
incremental: true,
split: attribute.label,
relative_to_struct: relative ? attribute.label : undefined,
}
_.extend(params, settings.corpusListing.getWithinParameters())

_.extend(params, cqpSubExprs)

const data = await korpRequest<KorpStatsResponse>("count", params)
...settings.corpusListing.getWithinParameters(),
...cqpSubExprs,
})

if ("ERROR" in data) {
// TODO Create a KorpBackendError which could be displayed nicely
Expand All @@ -161,10 +145,7 @@ export async function requestMapData(
return { corpora: attribute.corpora, cqp, within, data: result, attribute }
}

export async function getDataForReadingMode(
inputCorpus: string,
textId: string
): Promise<KorpResponse<KorpQueryResponse>> {
export async function getDataForReadingMode(inputCorpus: string, textId: string): Promise<KorpResponse<QueryResponse>> {
const corpus = inputCorpus.toUpperCase()
const corpusSettings = settings.corpusListing.get(inputCorpus)

Expand All @@ -187,5 +168,5 @@ export async function getDataForReadingMode(
end: 0,
}

return korpRequest<KorpQueryResponse>("query", params)
return korpRequest<QueryResponse>("query", params)
}
123 changes: 123 additions & 0 deletions app/scripts/backend/client.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
/** @format */

import { getAuthorizationHeader } from "@/components/auth/auth"
import { httpConfAddMethodFetch } from "@/util"
import { ApiKwic, KorpResponse, StatsColumn } from "@/backend/types"
import settings from "@/settings"

async function korpRequest<T extends Record<string, any> = {}, P extends Record<string, any> = {}>(
endpoint: string,
params: P
): Promise<KorpResponse<T>> {
const { url, request } = httpConfAddMethodFetch(settings.korp_backend_url + "/" + endpoint, params)
request.headers = { ...request.headers, ...getAuthorizationHeader() }
const response = await fetch(url, request)
return (await response.json()) as KorpResponse<T>
}

/** @see https://ws.spraakbanken.gu.se/docs/korp#tag/Misc/paths/~1loglike/get */
export type LoglikeResponse = {
/** Log-likelihood average. */
average: number
/** Log-likelihood values. */
loglike: Record<string, number>
/** Absolute frequency for the values in set 1. */
set1: Record<string, number>
/** Absolute frequency for the values in set 2. */
set2: Record<string, number>
}

/** @see https://ws.spraakbanken.gu.se/docs/korp#tag/Misc/paths/~1loglike/get */
export type LoglikeParams = {
group_by: string
set1_corpus: string
set1_cqp: string
set2_corpus: string
set2_cqp: string
max: `${number}`
split: string
top: string
}

export const loglike = (params: LoglikeParams) => korpRequest<LoglikeResponse>("loglike", params)

/** @see https://ws.spraakbanken.gu.se/docs/korp#tag/Statistics/paths/~1count/get */
export type CountParams = {
/** Corpus names, separated by comma */
corpus: string
/** CQP query */
cqp: string
/** Positional attribute by which the hits should be grouped. Defaults to "word" if neither `group_by` nor `group_by_struct` is defined */
group_by?: string
/** Structural attribute by which the hits should be grouped. The value for the first token of the hit will be used */
group_by_struct?: string
/** Prevent search from crossing boundaries of the given structural attribute, e.g. 'sentence'. */
default_within?: string
/** Like default_within, but for specific corpora, overriding the default. Specified using the format 'corpus:attribute' */
within?: string
ignore_case?: string
relative_to_struct?: string
split?: string
top?: string
[cqpn: `cqp${number}`]: string
expand_prequeries?: boolean
[subcqpn: `subcqp${number}`]: string
start?: number
end?: number
/** Incrementally return progress updates when the calculation for each corpus is finished */
incremental?: boolean
}

/** @see https://ws.spraakbanken.gu.se/docs/korp#tag/Statistics/paths/~1count/get */
export type CountResponse = {
corpora: {
[name: string]: StatsColumn | StatsColumn[]
}
combined: StatsColumn | StatsColumn[]
/** Total number of different values */
count: number
/** Execution time in seconds */
time: number
}

export const count = (params: CountParams) => korpRequest<CountResponse>("count", params)

/** @see https://ws.spraakbanken.gu.se/docs/korp#tag/Concordance/paths/~1query/get */
export type QueryParams = {
corpus: string
cqp: string
start?: number
end?: number
default_context?: string
context?: string
show?: string
show_struct?: string
default_within?: string
within?: string
in_order?: boolean
sort?: string
random_seed?: number
cut?: number
[cqpn: `cqp${number}`]: string
expand_prequeries?: boolean
incremental?: boolean
query_data?: string
}

/** @see https://ws.spraakbanken.gu.se/docs/korp#tag/Concordance/paths/~1query/get */
export type QueryResponse = {
/** Search hits */
kwic: ApiKwic[]
/** Total number of hits */
hits: number
/** Number of hits for each corpus */
corpus_hits: Record<string, number>
/** Order of corpora in result */
corpus_order: string[]
/** Execution time in seconds */
time: number
/** A hash of this query */
query_data: string
}

export const query = (params: QueryParams) => korpRequest<QueryResponse>("query", params)
3 changes: 1 addition & 2 deletions app/scripts/backend/graph-proxy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@
import _ from "lodash"
import settings from "@/settings"
import BaseProxy from "@/backend/base-proxy"
import { AjaxSettings, Granularity, Histogram, KorpResponse, NumericString } from "@/backend/types"
import { AbsRelTuple } from "@/statistics.types"
import { AbsRelTuple, AjaxSettings, Granularity, Histogram, KorpResponse, NumericString } from "@/backend/types"
import { Factory, httpConfAddMethod } from "@/util"

export class GraphProxy extends BaseProxy<KorpCountTimeResponse> {
Expand Down
94 changes: 12 additions & 82 deletions app/scripts/backend/kwic-proxy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@
import _ from "lodash"
import settings from "@/settings"
import BaseProxy from "@/backend/base-proxy"
import type { AjaxSettings, KorpResponse, ProgressReport, ProgressResponse } from "@/backend/types"
import type { AjaxSettings, KorpResponse, ProgressReport } from "@/backend/types"
import { locationSearchGet, httpConfAddMethod, Factory } from "@/util"
import { QueryParams, QueryResponse } from "./client"

export class KwicProxy extends BaseProxy<KorpQueryResponse> {
export class KwicProxy extends BaseProxy<QueryResponse> {
foundKwic: boolean
prevCQP?: string
prevParams: KorpQueryParams | null
prevParams: QueryParams | null
prevRequest: JQuery.AjaxSettings | null
prevUrl?: string
queryData?: string
Expand All @@ -24,9 +25,9 @@ export class KwicProxy extends BaseProxy<KorpQueryResponse> {
makeRequest(
options: KorpQueryRequestOptions,
page: number | undefined,
progressCallback: (data: ProgressReport<KorpQueryResponse>) => void,
kwicCallback: (data: KorpResponse<KorpQueryResponse>) => void
): JQuery.jqXHR<KorpResponse<KorpQueryResponse>> {
progressCallback: (data: ProgressReport<QueryResponse>) => void,
kwicCallback: (data: KorpResponse<QueryResponse>) => void
): JQuery.jqXHR<KorpResponse<QueryResponse>> {
const self = this
this.foundKwic = false
this.resetRequest()
Expand All @@ -49,7 +50,7 @@ export class KwicProxy extends BaseProxy<KorpQueryResponse> {

const command = options.ajaxParams.command || "query"

const data: KorpQueryParams = {
const data: QueryParams = {
default_context: settings.default_overview_context,
...getPageInterval(),
...options.ajaxParams,
Expand Down Expand Up @@ -103,7 +104,7 @@ export class KwicProxy extends BaseProxy<KorpQueryResponse> {
self.prevUrl = self.makeUrlWithParams(this.url, data)
},

success(data: KorpQueryResponse, status, jqxhr) {
success(data: QueryResponse, status, jqxhr) {
self.queryData = data.query_data
self.cleanup()
// TODO Should be `options.ajaxParams.incremental`?
Expand All @@ -119,12 +120,12 @@ export class KwicProxy extends BaseProxy<KorpQueryResponse> {
progressCallback(progressObj)
if ("kwic" in progressObj.struct) {
this.foundKwic = true
return kwicCallback(progressObj.struct as KorpQueryResponse)
return kwicCallback(progressObj.struct as QueryResponse)
}
},
}

const def = $.ajax(httpConfAddMethod(ajaxSettings)) as JQuery.jqXHR<KorpResponse<KorpQueryResponse>>
const def = $.ajax(httpConfAddMethod(ajaxSettings)) as JQuery.jqXHR<KorpResponse<QueryResponse>>
this.pendingRequests.push(def)
return def
}
Expand All @@ -133,84 +134,13 @@ export class KwicProxy extends BaseProxy<KorpQueryResponse> {
const kwicProxyFactory = new Factory(KwicProxy)
export default kwicProxyFactory

/** @see https://ws.spraakbanken.gu.se/docs/korp#tag/Concordance/paths/~1query/get */
export type KorpQueryParams = {
corpus: string
cqp: string
start?: number
end?: number
default_context?: string
context?: string
show?: string
show_struct?: string
default_within?: string
within?: string
in_order?: boolean
sort?: string
random_seed?: number
cut?: number
[cqpn: `cqp${number}`]: string
expand_prequeries?: boolean
incremental?: boolean
query_data?: string
}

export type KorpQueryRequestOptions = {
// TODO Should start,end really exist here as well as under ajaxParams?
start?: number
end?: number
ajaxParams: KorpQueryParams & {
ajaxParams: QueryParams & {
command?: string
}
}

type Interval = { start: number; end: number }

/** @see https://ws.spraakbanken.gu.se/docs/korp#tag/Concordance/paths/~1query/get */
export type KorpQueryResponse = {
/** Search hits */
kwic: ApiKwic[]
/** Total number of hits */
hits: number
/** Number of hits for each corpus */
corpus_hits: Record<string, number>
/** Order of corpora in result */
corpus_order: string[]
/** Execution time in seconds */
time: number
/** A hash of this query */
query_data: string
}

/** Search hits */
export type ApiKwic = {
/** An object for each token in the context, with attribute values for that token */
tokens: Token[]
/** Attribute values for the context (e.g. sentence) */
structs: Record<string, any>
/** Specifies the position of the match in the context. If `in_order` is false, `match` will consist of a list of match objects, one per highlighted word */
match: KwicMatch | KwicMatch[]
/** Hits from aligned corpora if available, otherwise omitted */
aligned: {
[linkedCorpusId: `${string}-${string}`]: Record<string, any>[]
}
}

/** Specifies the position of a match in a context */
type KwicMatch = {
/** Start position of the match within the context */
start: number
/** End position of the match within the context */
end: number
/** Global corpus position of the match */
position: number
}

export type Token = {
word: string
structs?: {
open?: Record<string, Record<string, string>>[]
close?: string[]
}
[attr: string]: any
}
Loading

0 comments on commit d44de2b

Please sign in to comment.