Skip to content

Commit

Permalink
Feature :: Sort step form (#228)
Browse files Browse the repository at this point in the history
- simplify the mongo transformation, now the order property is includes in columns
- introduce a new object in steps.ts `SortColumnType` 
- change steps documentation about that
- introduce a new widget : `WidgetSortColumn` for widgetList
  • Loading branch information
zegonz authored and adimascio committed Jul 12, 2019
1 parent cd31b7a commit 2e840a8
Show file tree
Hide file tree
Showing 15 changed files with 393 additions and 78 deletions.
45 changes: 4 additions & 41 deletions doc/steps.md
Original file line number Diff line number Diff line change
Expand Up @@ -734,52 +734,16 @@ the `select` is used, it will only keep selected columns in the output.
### `sort` step

Sort values in one or several columns. Order can be either 'asc' or 'desc'.
When sorting on several columns, order of columns specified in `columns` matters,
and the `order` parameter must be of same length as `columns`. By default, if
`order` is not specified, it is considered as 'asc'.
When sorting on several columns, order of columns specified in `columns` matters.

```javascript
{
name: 'sort',
columns: ['foo', 'bar'],
order: ['asc', 'desc']
columns: [{column: 'foo', order: 'asc'}, {column: 'bar', order: 'desc'}],
}
```

#### Example 1: sort on one column with default ordering

**Input dataset:**

| Label | Group | Value |
| ------- | ------- | ----- |
| Label 1 | Group 1 | 13 |
| Label 2 | Group 1 | 7 |
| Label 3 | Group 1 | 20 |
| Label 4 | Group 2 | 1 |
| Label 5 | Group 2 | 10 |
| Label 6 | Group 2 | 5 |

**Step configuration:**

```javascript
{
name: 'sort',
columns: ['Value'],
}
```

**Output dataset:**

| Company | Group | Value |
| ------- | ------- | ----- |
| Label 4 | Group 2 | 1 |
| Label 6 | Group 2 | 5 |
| Label 2 | Group 1 | 7 |
| Label 5 | Group 2 | 10 |
| Label 1 | Group 1 | 13 |
| Label 3 | Group 1 | 20 |

#### Example 2: sort on one column with default ordering
#### Example

**Input dataset:**

Expand All @@ -797,8 +761,7 @@ and the `order` parameter must be of same length as `columns`. By default, if
```javascript
{
name: 'sort',
columns: ['Group', 'Value'],
order: ['asc', 'desc'],
columns: [{ column: 'Group', order: 'asc'}, {column: 'Value', order: 'desc' }]
}
```

Expand Down
1 change: 1 addition & 0 deletions src/components/ActionMenu.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
<div class="action-menu__option" @click="createDeleteColumnStep">Delete column</div>
<div class="action-menu__option" @click="createStep('fillna')">Fill null values</div>
<div class="action-menu__option" @click="createStep('filter')">Filter values</div>
<div class="action-menu__option" @click="createStep('sort')">Sort values</div>
</div>
</div>
</popover>
Expand Down
63 changes: 63 additions & 0 deletions src/components/stepforms/SortStepForm.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
<template>
<div>
<step-form-title :title="title"></step-form-title>

<WidgetList
addFieldName="Add Column"
id="sortColumn"
v-model="sortColumns"
:defaultItem="defaultSortColumn"
:widget="widgetSortColumn"
:automatic-new-field="false"
></WidgetList>

<step-form-buttonbar :errors="errors" :cancel="cancelEdition" :submit="submit"></step-form-buttonbar>
</div>
</template>

<script lang="ts">
import { Prop } from 'vue-property-decorator';
import { SortStep } from '@/lib/steps';
import BaseStepForm from './StepForm.vue';
import { StepFormComponent } from '@/components/formlib';
import WidgetList from './WidgetList.vue';
import { SortColumnType } from '@/lib/steps';
import WidgetSortColumn from './WidgetSortColumn.vue';
@StepFormComponent({
vqbstep: 'sort',
name: 'sort-step-form',
components: {
WidgetList,
WidgetSortColumn,
},
})
export default class SortStepForm extends BaseStepForm<SortStep> {
@Prop({ type: Object, default: () => ({ name: 'sort', columns: [] }) })
initialStepValue!: SortStep;
readonly title: string = 'Sort';
widgetSortColumn = WidgetSortColumn;
get defaultSortColumn() {
const column = this.selectedColumns.length === 0 ? '' : this.selectedColumns[0];
const sortColumn: SortColumnType = {
column,
order: 'asc',
};
return sortColumn;
}
get sortColumns() {
if (this.editedStep.columns.length) {
return this.editedStep.columns;
} else {
return [this.defaultSortColumn];
}
}
set sortColumns(newval) {
this.editedStep.columns = [...newval];
}
}
</script>
7 changes: 0 additions & 7 deletions src/components/stepforms/WidgetAggregation.vue
Original file line number Diff line number Diff line change
Expand Up @@ -76,10 +76,3 @@ export default class WidgetAggregation extends Vue {
margin-bottom: 8px;
}
</style>

<style lang="scss">
.widget-aggregation__container .widget-autocomplete__label {
margin-bottom: 0px;
width: 40%;
}
</style>
13 changes: 12 additions & 1 deletion src/components/stepforms/WidgetList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -155,4 +155,15 @@ export default class WidgetList extends Vue {
top: calc(50% - 16px);
cursor: pointer;
}
</style>
</style>
<style lang="scss">
.widget-list__container .widget-autocomplete__container {
align-items: center;
flex-direction: row;
margin-bottom: 8px;
}
.widget-list__container .widget-autocomplete__label {
margin-bottom: 0px;
width: 40%;
}
</style>
64 changes: 64 additions & 0 deletions src/components/stepforms/WidgetSortColumn.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
<template>
<fieldset class="widget-sort__container">
<WidgetAutocomplete
id="columnInput"
:options="columnNames"
v-model="sort.column"
name="Column"
placeholder="Enter a column"
@input="setSelectedColumns({ column: sort.column })"
></WidgetAutocomplete>
<WidgetAutocomplete
id="sortOrderInput"
v-model="sort.order"
name="Order"
:options="['asc', 'desc']"
placeholder="Order by"
></WidgetAutocomplete>
</fieldset>
</template>
<script lang="ts">
import _ from 'lodash';
import { Component, Prop, Vue, Watch } from 'vue-property-decorator';
import { Getter, Mutation } from 'vuex-class';
import { MutationCallbacks } from '@/store/mutations';
import WidgetAutocomplete from './WidgetAutocomplete.vue';
import { SortColumnType } from '@/lib/steps';
const defaultValues: SortColumnType = {
column: '',
order: 'asc',
};
@Component({
name: 'widget-sort-column',
components: {
WidgetAutocomplete,
},
})
export default class WidgetSortColumn extends Vue {
@Prop({
type: Object,
default: () => ({
column: '',
order: 'asc',
}),
})
value!: SortColumnType;
@Getter columnNames!: string[];
@Mutation setSelectedColumns!: MutationCallbacks['setSelectedColumns'];
sort: SortColumnType = { ...this.value };
@Watch('value', { immediate: true, deep: true })
onSortChanged(newval: SortColumnType, oldval: SortColumnType) {
if (!_.isEqual(newval, oldval)) {
this.sort = { ...newval };
this.$emit('input', this.sort);
}
}
}
</script>

1 change: 1 addition & 0 deletions src/components/stepforms/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ import './RenameStepForm.vue';
import './SelectColumnStepForm.vue';
import './TopStepForm.vue';
import './UnpivotStepForm.vue';
import './SortStepForm.vue';
2 changes: 2 additions & 0 deletions src/components/stepforms/schemas/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import renameBuildSchema from './rename';
import selectSchema from './select';
import topBuildSchema from './top';
import unpivotSchema from './unpivot';
import sortSchema from './sort';

type buildSchemaType = ((form: any) => object) | object;

Expand All @@ -30,6 +31,7 @@ const factories: { [stepname: string]: buildSchemaType } = {
select: selectSchema,
top: topBuildSchema,
unpivot: unpivotSchema,
sort: sortSchema,
};

/**
Expand Down
37 changes: 37 additions & 0 deletions src/components/stepforms/schemas/sort.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
export default {
$schema: 'http://json-schema.org/draft-07/schema#',
title: 'Sort column step',
type: 'object',
properties: {
name: {
type: 'string',
enum: ['sort'],
},
columns: {
type: 'array',
minItems: 1,
title: 'Columns to sort',
description: 'Columns to sort',
attrs: {
placeholder: 'Enter columns',
},
items: {
type: 'object',
title: 'Column to sort',
description: 'Column to sort',
properties: {
column: {
type: 'string',
minLength: 1,
},
order: {
type: 'string',
enum: ['asc', 'desc'],
},
},
},
},
},
required: ['name', 'columns'],
additionalProperties: false,
};
8 changes: 6 additions & 2 deletions src/lib/steps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,10 +106,14 @@ export type SelectStep = {
columns: string[];
};

export type SortColumnType = {
column: string;
order: 'asc' | 'desc';
};

export type SortStep = {
name: 'sort';
columns: string[];
order?: ('asc' | 'desc')[];
columns: SortColumnType[];
};

export type TopStep = {
Expand Down
6 changes: 2 additions & 4 deletions src/lib/translators/mongo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -248,10 +248,8 @@ function transformReplace(step: Readonly<ReplaceStep>): MongoStep {
/** transform a 'sort' step into corresponding mongo steps */
function transformSort(step: Readonly<SortStep>): MongoStep {
const sortMongo: PropMap<number> = {};
const sortOrders = step.order === undefined ? Array(step.columns.length).fill('asc') : step.order;
for (let i = 0; i < step.columns.length; i++) {
const order = sortOrders[i] === 'asc' ? 1 : -1;
sortMongo[step.columns[i]] = order;
for (const sortColumn of step.columns) {
sortMongo[sortColumn.column] = sortColumn.order === 'asc' ? 1 : -1;
}
return { $sort: sortMongo };
}
Expand Down
4 changes: 3 additions & 1 deletion tests/unit/karma-test-suite.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import './plugins.spec';
import './popover.spec';
import './rename-step-form.spec';
import './resizable-panels.spec';
import './sort-step-form.spec';
import './step.spec';
import './store.spec';
import './top-step-form.spec';
Expand All @@ -33,4 +34,5 @@ import './widget-autocomplete.spec';
import './widget-checkbox.spec';
import './widget-input-text.spec';
import './widget-list.spec';
import './widget-multiselect.spec.ts';
import './widget-multiselect.spec';
import './widget-sort-column.spec';
24 changes: 2 additions & 22 deletions tests/unit/mongo.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -471,8 +471,7 @@ describe('Pipeline to mongo translator', () => {
const pipeline: Pipeline = [
{
name: 'sort',
columns: ['foo'],
order: ['desc'],
columns: [{ column: 'foo', order: 'desc' }],
},
];
const querySteps = mongo36translator.translate(pipeline);
Expand All @@ -489,8 +488,7 @@ describe('Pipeline to mongo translator', () => {
const pipeline: Pipeline = [
{
name: 'sort',
columns: ['foo', 'bar'],
order: ['asc', 'desc'],
columns: [{ column: 'foo', order: 'asc' }, { column: 'bar', order: 'desc' }],
},
];
const querySteps = mongo36translator.translate(pipeline);
Expand All @@ -504,24 +502,6 @@ describe('Pipeline to mongo translator', () => {
]);
});

it('can generate a sort step on multiple columns with default order', () => {
const pipeline: Pipeline = [
{
name: 'sort',
columns: ['foo', 'bar'],
},
];
const querySteps = mongo36translator.translate(pipeline);
expect(querySteps).to.eql([
{
$sort: {
foo: 1,
bar: 1,
},
},
]);
});

it('can generate a fillna step', () => {
const pipeline: Pipeline = [
{
Expand Down
Loading

0 comments on commit 2e840a8

Please sign in to comment.