perspective display test WIP

This commit is contained in:
Jan Prochazka
2022-07-31 08:11:04 +02:00
parent 27b2fdb507
commit d686206fe2
11 changed files with 2094 additions and 35 deletions

View File

@@ -0,0 +1,5 @@
module.exports = {
preset: 'ts-jest',
testEnvironment: 'node',
moduleFileExtensions: ['js'],
};

View File

@@ -5,6 +5,7 @@
"typings": "lib/index.d.ts",
"scripts": {
"build": "tsc",
"test": "jest",
"start": "tsc --watch"
},
"files": [
@@ -18,6 +19,8 @@
"devDependencies": {
"dbgate-types": "^5.0.0-alpha.1",
"@types/node": "^13.7.0",
"jest": "^28.1.3",
"ts-jest": "^28.0.7",
"typescript": "^4.4.3"
}
}

View File

@@ -7,9 +7,9 @@ import debug from 'debug';
const dbg = debug('dbgate:PerspectiveDisplay');
const SKIP_CELL = {
__perspective_skip_cell__: true,
};
// const SKIP_CELL = {
// __perspective_skip_cell__: true,
// };
let lastJoinId = 0;
function getJoinId(): number {
@@ -74,6 +74,7 @@ export class PerspectiveDisplayRow {
this.rowData = _fill(Array(display.columns.length), undefined);
this.rowSpans = _fill(Array(display.columns.length), 1);
this.rowJoinIds = _fill(Array(display.columns.length), 0);
this.rowCellSkips = _fill(Array(display.columns.length), false);
}
getRow(rowIndex): PerspectiveDisplayRow {
@@ -95,6 +96,8 @@ export class PerspectiveDisplayRow {
rowData: any[] = [];
rowSpans: number[] = null;
rowCellSkips: boolean[] = null;
rowJoinIds: number[] = [];
incompleteRowsIndicator: string[] = null;
}
@@ -113,19 +116,19 @@ export class PerspectiveDisplay {
this.columnLevelCount = _max(this.columns.map(x => x.parentNodes.length)) + 1;
const collectedRows = this.collectRows(rows, root.childNodes);
// dbg('collected rows', collectedRows);
// console.log('COLLECTED', collectedRows);
// console.log('COLLECTED', JSON.stringify(collectedRows, null, 2));
// this.mergeRows(collectedRows);
this.mergeRows(collectedRows);
// dbg('merged rows', this.rows);
// console.log(
// 'MERGED',
// this.rows.map(r =>
// r.incompleteRowsIndicator
// ? `************************************ ${r.incompleteRowsIndicator.join('|')}`
// : r.rowData.join('|')
// )
// );
console.log(
'MERGED',
this.rows.map(r =>
r.incompleteRowsIndicator
? `************************************ ${r.incompleteRowsIndicator.join('|')}`
: r.rowData.join('|')
)
);
}
fillColumns(children: PerspectiveTreeNode[], parentNodes: PerspectiveTreeNode[]) {
@@ -212,7 +215,7 @@ export class PerspectiveDisplay {
row.rowJoinIds[col] == this.rows[lastFilledRow].rowJoinIds[col] &&
row.rowJoinIds[col]
) {
row.rowData[col] = SKIP_CELL;
row.rowCellSkips[col] = true;
this.rows[lastFilledRow].rowSpans[col] = rowIndex - lastFilledRow + 1;
} else {
lastFilledRow = rowIndex;
@@ -229,6 +232,8 @@ export class PerspectiveDisplay {
this.mergeRow(collectedRow, resultRow);
rows.push(resultRow);
}
// console.log('MERGED NOT FLAT', rows);
console.log('MERGED NOT FLAT SUBROWS 0', rows[0].subrows[0]);
for (const row of rows) {
this.flushFlatRows(row);
}
@@ -244,7 +249,7 @@ export class PerspectiveDisplay {
}
resultRow.incompleteRowsIndicator = collectedRow.incompleteRowsIndicator;
let subRowCount = 0;
// let subRowCount = 0;
for (const subrows of collectedRow.subRowCollections) {
let rowIndex = 0;
for (const subrow of subrows.rows) {
@@ -252,9 +257,9 @@ export class PerspectiveDisplay {
this.mergeRow(subrow, targetRow);
rowIndex++;
}
if (rowIndex > subRowCount) {
subRowCount = rowIndex;
}
// if (rowIndex > subRowCount) {
// subRowCount = rowIndex;
// }
}
const joinId = getJoinId();

View File

@@ -0,0 +1,88 @@
import { TableInfo } from 'dbgate-types';
import { PerspectiveDisplay } from '../PerspectiveDisplay';
import { PerspectiveTableNode } from '../PerspectiveTreeNode';
import { chinookDbInfo } from './chinookDbInfo';
import { createPerspectiveConfig } from '../PerspectiveConfig';
import artistDataFlat from './artistDataFlat';
import artistDataAlbum from './artistDataAlbum';
import artistDataAlbumTrack from './artistDataAlbumTrack';
test('test flat view', () => {
const artistTable = chinookDbInfo.tables.find(x => x.pureName == 'Artist');
const root = new PerspectiveTableNode(artistTable, chinookDbInfo, createPerspectiveConfig(), null, null, null, null);
const display = new PerspectiveDisplay(root, artistDataFlat);
console.log(display.rows);
expect(display.rows.length).toEqual(5);
expect(display.rows[0]).toEqual(
expect.objectContaining({
rowData: ['AC/DC'],
})
);
});
test('test one level nesting', () => {
const artistTable = chinookDbInfo.tables.find(x => x.pureName == 'Artist');
const root = new PerspectiveTableNode(
artistTable,
chinookDbInfo,
{ ...createPerspectiveConfig(), checkedColumns: ['Artist.Album'] },
null,
null,
null,
null
);
const display = new PerspectiveDisplay(root, artistDataAlbum);
console.log(display.rows);
expect(display.rows.length).toEqual(7);
expect(display.rows[0]).toEqual(
expect.objectContaining({
rowData: ['AC/DC', 'For Those About To Rock We Salute You'],
rowSpans: [2, 1],
rowCellSkips: [false, false],
})
);
expect(display.rows[1]).toEqual(
expect.objectContaining({
rowData: [undefined, 'Let There Be Rock'],
rowSpans: [1, 1],
rowCellSkips: [true, false],
})
);
expect(display.rows[5]).toEqual(
expect.objectContaining({
rowData: ['Alanis Morissette', 'Jagged Little Pill'],
rowSpans: [1, 1],
})
);
});
test('test two level nesting', () => {
const artistTable = chinookDbInfo.tables.find(x => x.pureName == 'Artist');
const root = new PerspectiveTableNode(
artistTable,
chinookDbInfo,
{ ...createPerspectiveConfig(), checkedColumns: ['Artist.Album', 'Artist.Album.Track'] },
null,
null,
null,
null
);
const display = new PerspectiveDisplay(root, artistDataAlbumTrack);
console.log(display.rows);
expect(display.rows.length).toEqual(9);
// expect(display.rows[0]).toEqual(
// expect.objectContaining({
// rowData: ['AC/DC', 'For Those About To Rock We Salute You'],
// rowSpans: [2, 1],
// })
// );
// expect(display.rows[5]).toEqual(
// expect.objectContaining({
// rowData: ['Alanis Morissette', 'Jagged Little Pill'],
// rowSpans: [1, 1],
// })
// );
});

View File

@@ -0,0 +1,55 @@
export default [
{
"ArtistId": 1,
"Name": "AC/DC",
"Album": [
{
"Title": "For Those About To Rock We Salute You",
"ArtistId": 1
},
{
"Title": "Let There Be Rock",
"ArtistId": 1
}
]
},
{
"ArtistId": 2,
"Name": "Accept",
"Album": [
{
"Title": "Balls to the Wall",
"ArtistId": 2
},
{
"Title": "Restless and Wild",
"ArtistId": 2
}
]
},
{
"ArtistId": 3,
"Name": "Aerosmith",
"Album": [
{
"Title": "Big Ones",
"ArtistId": 3
}
]
},
{
"ArtistId": 4,
"Name": "Alanis Morissette",
"Album": [
{
"Title": "Jagged Little Pill",
"ArtistId": 4
}
]
},
{
"incompleteRowsIndicator": [
"Artist"
]
}
]

View File

@@ -0,0 +1,78 @@
export default [
{
ArtistId: 1,
Name: 'AC/DC',
Album: [
{
Title: 'For Those About To Rock We Salute You',
AlbumId: 1,
ArtistId: 1,
Track: [
{
Name: 'For Those About To Rock (We Salute You)',
AlbumId: 1,
},
{
Name: 'Put The Finger On You',
AlbumId: 1,
},
],
},
{
Title: 'Let There Be Rock',
AlbumId: 4,
ArtistId: 1,
Track: [
{
Name: 'Go Down',
AlbumId: 4,
},
{
Name: 'Dog Eat Dog',
AlbumId: 4,
},
],
},
],
},
{
ArtistId: 2,
Name: 'Accept',
Album: [
{
Title: 'Balls to the Wall',
AlbumId: 2,
ArtistId: 2,
Track: [
{
Name: 'Balls to the Wall',
AlbumId: 2,
},
],
},
{
Title: 'Restless and Wild',
AlbumId: 3,
ArtistId: 2,
Track: [
{
Name: 'Fast As a Shark',
AlbumId: 3,
},
{
Name: 'Restless and Wild',
AlbumId: 3,
},
{
Name: 'Princess of the Dawn',
AlbumId: 3,
},
],
},
],
},
{
incompleteRowsIndicator: ['Artist'],
},
];

View File

@@ -0,0 +1,21 @@
export default [
{
ArtistId: 1,
Name: 'AC/DC',
},
{
ArtistId: 2,
Name: 'Accept',
},
{
ArtistId: 3,
Name: 'Aerosmith',
},
{
ArtistId: 4,
Name: 'Alanis Morissette',
},
{
incompleteRowsIndicator: ['Artist'],
},
];

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,8 @@
export interface NamedObjectInfo {
pureName: string;
schemaName?: string;
contentHash?: string;
engine?: string;
}
export interface ColumnReference {
@@ -31,7 +33,8 @@ export interface ForeignKeyInfo extends ColumnsConstraintInfo {
export interface IndexInfo extends ColumnsConstraintInfo {
isUnique: boolean;
indexType: 'normal' | 'clustered' | 'xml' | 'spatial' | 'fulltext';
// indexType: 'normal' | 'clustered' | 'xml' | 'spatial' | 'fulltext';
indexType: string;
}
export interface UniqueInfo extends ColumnsConstraintInfo {}
@@ -43,8 +46,8 @@ export interface CheckInfo extends ConstraintInfo {
export interface ColumnInfo extends NamedObjectInfo {
pairingId?: string;
columnName: string;
notNull: boolean;
autoIncrement: boolean;
notNull?: boolean;
autoIncrement?: boolean;
dataType: string;
precision?: number;
scale?: number;
@@ -119,7 +122,7 @@ export interface DatabaseInfoObjects {
}
export interface DatabaseInfo extends DatabaseInfoObjects {
schemas: SchemaInfo[];
schemas?: SchemaInfo[];
engine?: string;
defaultSchema?: string;
}

View File

@@ -1,3 +1,16 @@
<script lang="ts" context="module">
const getCurrentEditor = () => getActiveComponent('PerspectiveTable');
registerCommand({
id: 'perspective.openJson',
category: 'Perspective',
name: 'Open JSON',
isRelatedToTab: true,
testEnabled: () => getCurrentEditor()?.openJsonEnabled(),
onClick: () => getCurrentEditor().openJson(),
});
</script>
<script lang="ts">
import { PerspectiveDisplay, PerspectiveTreeNode } from 'dbgate-datalib';
import _ from 'lodash';
@@ -9,8 +22,12 @@
import DataFilterControl from '../datagrid/DataFilterControl.svelte';
import ErrorInfo from '../elements/ErrorInfo.svelte';
import FormStyledButton from '../buttons/FormStyledButton.svelte';
import registerCommand from '../commands/registerCommand';
import createActivator, { getActiveComponent } from '../utility/createActivator';
import { openJsonDocument } from '../tabs/JsonTab.svelte';
const dbg = debug('dbgate:PerspectivaTable');
export const activator = createActivator('PerspectiveTable', true);
export let root: PerspectiveTreeNode;
export let loadedCounts;
@@ -104,6 +121,14 @@
// }
}
export function openJson() {
openJsonDocument(dataRows);
}
export function openJsonEnabled() {
return dataRows != null;
}
onMount(() => {});
$: loadData(root, $loadedCounts);
@@ -114,6 +139,9 @@
{
command: 'perspective.refresh',
},
{
command: 'perspective.openJson',
},
];
}
</script>
@@ -129,7 +157,7 @@
<th rowspan={column.rowSpan}>{column.title}</th>
{/if}
{#if column.showParent(columnLevel)}
<th colspan={column.getColSpan(columnLevel)} class='tableName'>{column.getParentName(columnLevel)}</th>
<th colspan={column.getColSpan(columnLevel)} class="tableName">{column.getParentName(columnLevel)}</th>
{/if}
{/each}
</tr>
@@ -169,10 +197,12 @@
{:else}
{#each display.columns as column}
<!-- <td>{row.rowSpans[column.columnIndex]} {row.rowData[column.columnIndex]}</td> -->
{#if row.rowData[column.columnIndex] === undefined}
<td />
{:else if !row.rowData[column.columnIndex]?.__perspective_skip_cell__}
<td rowspan={row.rowSpans[column.columnIndex]}>{row.rowData[column.columnIndex]}</td>
{#if !row.rowCellSkips[column.columnIndex]}
{#if row.rowData[column.columnIndex] === undefined}
<td />
{:else}
<td rowspan={row.rowSpans[column.columnIndex]}>{row.rowData[column.columnIndex]}</td>
{/if}
{/if}
{/each}
{/if}

View File

@@ -59,16 +59,10 @@
$: dataProvider = new PerspectiveDataProvider(cache, loader);
$: loader = new PerspectiveDataLoader(apiCall);
$: root = $tableInfo
? new PerspectiveTableNode(
$tableInfo,
$dbInfo,
config,
setConfig,
dataProvider,
{ conid, database },
null
)
? new PerspectiveTableNode($tableInfo, $dbInfo, config, setConfig, dataProvider, { conid, database }, null)
: null;
// $: console.log('CONFIG', config);
</script>
<HorizontalSplitter initialValue={getInitialManagerSize()} bind:size={managerSize}>