src/RelOp.js
// @flow
import React from 'react';
import type {Element, Node, StatelessFunctionalComponent} from 'react';
import type {OrderByColumn} from './modules/relexp';
type Props = {
children: Node,
};
/** Base for all relational algebra operators */
const RelOp: StatelessFunctionalComponent<Props> = (props) => {
return <span>{props.children}</span>;
};
export default RelOp;
type UnaryProps = {
operator: Element<any>,
children: Node,
};
const UnaryRelOpInternal: StatelessFunctionalComponent<UnaryProps> = (
props
) => (
<span>
{props.operator}({props.children})
</span>
);
export const UnaryRelOp: StatelessFunctionalComponent<UnaryProps> = (props) => (
<RelOp>
<UnaryRelOpInternal operator={props.operator} children={props.children} />
</RelOp>
);
/** Projection relational algebra operator */
export const Projection: StatelessFunctionalComponent<{
project: Array<string>,
}> = (props) => (
<span>
π<sub>{props.project.join(',')}</sub>
</span>
);
/** Rename relational algebra operator */
export const Rename: StatelessFunctionalComponent<{
rename: {[string]: any},
}> = (props) => (
<span>
ρ
<sub>
{/* Loop over all columns to rename and combine them */}
{Object.entries(props.rename.columns)
.map(([o, n]) => {
return o + '/' + ((n: any): string);
})
.join(',')}
</sub>
</span>
);
/** Selection relational algebra operator */
export const Selection: StatelessFunctionalComponent<{select: string}> = (
props
) => (
<span>
σ<sub>{props.select}</sub>
</span>
);
type BinaryProps = {
operator: Element<any>,
left: Node,
right: Node,
};
const BinaryRelOpInternal: StatelessFunctionalComponent<BinaryProps> = (
props
) => (
<span>
{props.left}
{props.operator}
{props.right}
</span>
);
export const BinaryRelOp: StatelessFunctionalComponent<BinaryProps> = (
props
) => (
<RelOp>
<BinaryRelOpInternal
left={props.left}
operator={props.operator}
right={props.right}
/>
</RelOp>
);
export const Except: StatelessFunctionalComponent<{||}> = () => (
<span>−</span>
);
export const Intersect: StatelessFunctionalComponent<{||}> = () => (
<span>∩</span>
);
export const OrderBy: StatelessFunctionalComponent<{
columns: Array<OrderByColumn>,
relation: Node,
}> = (props) => {
const columnSort = props.columns
.map((c) => c.column_name + (c.ascending ? ' ↑' : ' ↓'))
.join(', ');
return (
<span>
τ<sub>{columnSort}</sub> {props.relation}
</span>
);
};
export const Join: StatelessFunctionalComponent<{
type: string,
condition: string,
left?: Node,
right?: Node,
}> = (props) => {
if (props.type === 'left') {
return (
<span>
{props.left} ⟕<sub>{props.condition}</sub> {props.right}
</span>
);
} else if (props.type === 'right') {
return (
<span>
{props.left} ⟖<sub>{props.condition}</sub> {props.right}
</span>
);
} else {
return (
<span>
{props.left} ⋈<sub>{props.condition}</sub> {props.right}
</span>
);
}
};
export const Product: StatelessFunctionalComponent<{||}> = () => (
<span>×</span>
);
export const Union: StatelessFunctionalComponent<{||}> = () => (
<span>∪</span>
);
/** Group By relational algebra operator */
export const GroupBy: StatelessFunctionalComponent<{|
groupBy: Array<string>,
aggregates: Array<string>,
selectColumns?: Array<string>,
|}> = (props) => {
const resultColumns = [...(props.selectColumns || []), ...props.aggregates];
return (
<span>
{props.groupBy.length > 0 && <sub>{props.groupBy.join(',')}</sub>}
γ
<sub>{resultColumns.join(',')}</sub>
</span>
);
};