Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions packages/components/package-lock.json

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

2 changes: 1 addition & 1 deletion packages/components/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@labkey/components",
"version": "7.61.0",
"version": "7.62.0",
"description": "Components, models, actions, and utility functions for LabKey applications and pages",
"sideEffects": false,
"files": [
Expand Down
8 changes: 7 additions & 1 deletion packages/components/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1946,7 +1946,13 @@ export type {
ExecuteSqlResponseWithoutSession,
ExecuteSqlResponseWithSession,
} from './internal/query/executeSql';
export type { Row, RowValue, SelectRowsOptions, SelectRowsResponse } from './internal/query/selectRows';
export type {
Row,
RowValue,
SelectRowsMessage,
SelectRowsOptions,
SelectRowsResponse,
} from './internal/query/selectRows';
export type { IAttachment } from './internal/renderers/AttachmentCard';
export type { RequestHandler, RequestOptions } from './internal/request';
export type { AppContextTestProviderProps } from './internal/test/testHelpers';
Expand Down
69 changes: 33 additions & 36 deletions packages/components/src/internal/query/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import { URLResolver } from '../url/URLResolver';
import { ModuleContext } from '../components/base/ServerContext';
import { handleRequestFailure, RequestHandler } from '../request';
import { EDIT_METHOD } from '../constants';
import { Row } from './selectRows';

let queryDetailsCache: Record<string, Promise<QueryInfo>> = {};

Expand Down Expand Up @@ -442,9 +443,9 @@ export function isSelectRowMetadataRequired(includeMetadata?: boolean, columns?:
export interface ISelectRowsResult {
key: SchemaQueryKey;
messages?: List<Map<string, string>>;
models: any;
orderedModels: List<any>;
queries: Record<string, QueryInfo>;
models: Record<SchemaQueryKey, Record<string, Row>>;
orderedModels: Record<SchemaQueryKey, List<string>>;
queries: Record<SchemaQueryKey, QueryInfo>;
rowCount: number;
}

Expand Down Expand Up @@ -512,20 +513,16 @@ export async function selectRowsDeprecated(options_: SelectRowsDeprecatedOptions
};
}

export function handleSelectRowsResponse(response: Query.Response, queryInfo: QueryInfo): any {
const resolved = new URLResolver().resolveSelectRows(response, queryInfo);

let count = 0,
hasRows = false,
models = {},
orderedModels = {},
qsKey = 'queries',
rowCount = response.rowCount || 0;
export function resolveRowKey(
metaData: Query.ResponseMetadata | undefined,
queryInfo: QueryInfo
): { metadataAltKey: string; metadataKey: string } {
let metadataAltKey: string;
let metadataKey: string;

let metadataAltKey: string, metadataKey: string;
if (resolved.metaData) {
if (metaData) {
// If metaData is present, then use its "id" value regardless of presence of a queryInfo
metadataKey = resolved.metaData.id;
metadataKey = metaData.id;
} else if (queryInfo) {
// Match ApiQueryResponse logic for determining "metaData.id"
if (queryInfo.pkCols.length === 1) {
Expand All @@ -536,11 +533,24 @@ export function handleSelectRowsResponse(response: Query.Response, queryInfo: Qu
}
}
}

return { metadataAltKey, metadataKey };
}

export function handleSelectRowsResponse(response: Query.Response, queryInfo: QueryInfo): Partial<ISelectRowsResult> {
const resolved = new URLResolver().resolveSelectRows(response, queryInfo);
const { metadataAltKey, metadataKey } = resolveRowKey(resolved.metaData, queryInfo);
const modelKey = resolveKeyFromJson(resolved);
const models: Record<SchemaQueryKey, Record<string, Row>> = {};
const orderedModels: Record<SchemaQueryKey, List<string>> = {};
const qsKey = 'queries';

let count = 0;
const idAttribute = '_id_';

// ensure id -- unfortunately, with normalizr 3.x there doesn't seem to be a way to generate the id
// without attaching directly to the object
resolved.rows.forEach((row: any) => {
resolved.rows.forEach(row => {
if (metadataKey || metadataAltKey) {
const val = row[metadataKey] ?? row[metadataAltKey];
if (val !== undefined) {
Expand All @@ -550,38 +560,25 @@ export function handleSelectRowsResponse(response: Query.Response, queryInfo: Qu
console.error('Missing entry', metadataKey, row, resolved.schemaKey, resolved.queryName);
}
}
row._id_ = count++;
row[idAttribute] = count++;
});

const modelSchema = new schema.Entity(
modelKey,
{},
{
idAttribute: '_id_',
}
);

const querySchema = new schema.Entity(
qsKey,
{},
{
idAttribute: queryJson => resolveKeyFromJson(queryJson),
}
);
const modelSchema = new schema.Entity(modelKey, {}, { idAttribute });
const querySchema = new schema.Entity(qsKey, {}, { idAttribute: queryJson => resolveKeyFromJson(queryJson) });

querySchema.define({
rows: new schema.Array(modelSchema),
});
querySchema.define({ rows: new schema.Array(modelSchema) });

const instance = normalize(resolved, querySchema);
let hasRows = false;
let rowCount = response.rowCount || 0;

Object.keys(instance.entities).forEach(key => {
if (key !== qsKey) {
rowCount = instance.entities[qsKey][key].rowCount;
const rows = instance.entities[key];
// cleanup generated ids
Object.keys(rows).forEach(rowKey => {
delete rows[rowKey]['_id_'];
delete rows[rowKey][idAttribute];
});
models[key] = rows;
orderedModels[key] = fromJS(instance.entities[qsKey][key].rows)
Expand Down
11 changes: 10 additions & 1 deletion packages/components/src/internal/query/selectRows.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ import { URLResolver } from '../url/URLResolver';
import { getContainerFilter, getQueryDetails, isSelectRowMetadataRequired } from './api';
import { RequestHandler } from '../request';

export interface SelectRowsMessage {
area?: string;
content: string;
type?: string;
}

export interface SelectRowsOptions
extends Omit<
Query.SelectRowsOptions,
Expand All @@ -29,7 +35,9 @@ export interface RowValue {
export type Row = Record<string, RowValue>;

export interface SelectRowsResponse {
messages: Record<string, string>[];
messages: SelectRowsMessage[];
/** Only available when "includeMetadata" is set to true. */
metaData: Query.ResponseMetadata | undefined;
queryInfo: QueryInfo;
rowCount: number;
rows: Row[];
Expand Down Expand Up @@ -86,6 +94,7 @@ export async function selectRows(options: SelectRowsOptions): Promise<SelectRows
const resolved = new URLResolver().resolveSelectRows(response, queryInfo);

return {
metaData: response.metaData,
messages: resolved.messages,
queryInfo,
rows: resolved.rows,
Expand Down
12 changes: 3 additions & 9 deletions packages/components/src/public/QueryModel/QueryModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import { QueryColumn } from '../QueryColumn';
import { caseInsensitive } from '../../internal/util/utils';
import { naturalSortByProperty } from '../sort';
import { PaginationData } from '../../internal/components/pagination/Pagination';
import { SelectRowsOptions } from '../../internal/query/selectRows';
import { SelectRowsMessage, SelectRowsOptions } from '../../internal/query/selectRows';

export function flattenValuesFromRow(
row: any,
Expand Down Expand Up @@ -108,12 +108,6 @@ export function createQueryModelId(schemaQuery: SchemaQuery): string {

const sortStringMapper = (s: QuerySort): string => s.toRequestString();

export interface GridMessage {
area?: string;
content: string;
type?: string;
}

export enum SavedSettings {
all = 'all', // Restores filters, maxRows, sorts, and view
noFilters = 'noFilters', // Restores maxRows and sorts only
Expand Down Expand Up @@ -387,9 +381,9 @@ export class QueryModel {
readonly filterArray: Filter.IFilter[];
// QueryModel only fields
/**
* Array of [[GridMessage]]. When used with a [[GridPanel]], these message will be shown above the table of data rows.
* Array of [[SelectRowsMessage]]. When used with a [[GridPanel]], these messages will be shown above the table of data rows.
*/
readonly messages?: GridMessage[];
readonly messages?: SelectRowsMessage[];
/**
* Array of row key values in sort order from the loaded data rows object.
*/
Expand Down
Loading