import { observer } from 'mobx-react-lite'; import React, { useState, useRef, useMemo, useEffect } from 'react'; import { useVizStore } from '../../store'; import { isNotEmpty, parseErrorMessage } from '../../utils'; import { highlightField } from '../highlightField'; import { aggFuncs, reservedKeywords, sqlFunctions } from '../../lib/sql'; import { COUNT_FIELD_ID, MEA_KEY_ID, MEA_VAL_ID, PAINT_FIELD_ID } from '../../constants'; import { unstable_batchedUpdates } from 'react-dom'; import { Dialog, DialogContent } from '../ui/dialog'; import { Input } from '../ui/input'; import { Button } from '../ui/button'; const keywordRegex = new RegExp(`\\b(${Array.from(reservedKeywords).join('|')})\\b`, 'gi'); const bulitInRegex = new RegExp(`\\b(${Array.from(sqlFunctions).join('|')})(\\s*)\\(`, 'gi'); const aggBultinRegex = new RegExp(`\\b(${Array.from(aggFuncs).join('|')})(\\s*)\\(`, 'gi'); const stringRegex = /('[^']*'?)/g; const ComputedFieldDialog: React.FC = observer(() => { const vizStore = useVizStore(); const { editingComputedFieldFid } = vizStore; const [name, setName] = useState(''); const [sql, setSql] = useState(''); const [error, setError] = useState(''); const ref = useRef(null); const SQLField = useMemo(() => { const fields = vizStore.allFields .filter((x) => ![COUNT_FIELD_ID, MEA_KEY_ID, MEA_VAL_ID, PAINT_FIELD_ID].includes(x.fid)) .map((x) => x.name.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&')) .join('|'); const fieldRegex = fields.length > 0 ? new RegExp(`\\b(${fields})\\b`, 'gi') : null; return highlightField((sql: string) => { // highlight field if (fieldRegex) { sql = sql.replace(fieldRegex, '$1'); } // highlight keyword sql = sql.replace(keywordRegex, '$1'); // highlight function sql = sql.replace(bulitInRegex, '$1$2('); // highlight agg function sql = sql.replace(aggBultinRegex, '$1$2('); // highlight string sql = sql.replace(stringRegex, '$1'); return sql; }); }, [vizStore.allFields]); useEffect(() => { if (isNotEmpty(editingComputedFieldFid)) { if (editingComputedFieldFid === '') { let idx = 1; while (vizStore.allFields.find((x) => x.name === `Computed ${idx}`)) { idx++; } unstable_batchedUpdates(() => { setName(`Computed ${idx}`); setSql(''); setError(''); }); ref.current && (ref.current.innerHTML = ''); } else { const f = vizStore.allFields.find((x) => x.fid === editingComputedFieldFid); if (!f || !f.computed || f.expression?.op !== 'expr') { vizStore.setComputedFieldFid(''); return; } const sql = f.expression.params.find((x) => x.type === 'sql'); if (!sql) { vizStore.setComputedFieldFid(''); return; } unstable_batchedUpdates(() => { setName(f.name); setSql(sql.value); setError(''); }); ref.current && (ref.current.innerHTML = sql.value); } } }, [editingComputedFieldFid, vizStore]); if (!isNotEmpty(editingComputedFieldFid)) return null; return ( { vizStore.setComputedFieldFid(); }} >
{editingComputedFieldFid === '' ? 'Add Computed Field' : 'Edit Computed Field'}
Computed fields guide:{' '} read here
{ setName(e.target.value); }} />
{error &&
{error}
}
); }); export default ComputedFieldDialog;