import-export - work with schema (mssql)

This commit is contained in:
Jan Prochazka
2020-06-18 09:38:08 +02:00
parent 759754c437
commit a9ce93cd67
11 changed files with 73 additions and 23 deletions

View File

@@ -89,6 +89,7 @@ DatabaseAnalyser.createEmptyStructure = () => ({
functions: [], functions: [],
procedures: [], procedures: [],
triggers: [], triggers: [],
schemas: [],
}); });
DatabaseAnalyser.byTableFilter = (table) => (x) => x.pureName == table.pureName && x.schemaName == x.schemaName; DatabaseAnalyser.byTableFilter = (table) => (x) => x.pureName == table.pureName && x.schemaName == x.schemaName;

View File

@@ -168,7 +168,7 @@ class MsSqlAnalyser extends DatabaseAnalyser {
if (this.singleObjectFilter) { if (this.singleObjectFilter) {
const { typeField } = this.singleObjectFilter; const { typeField } = this.singleObjectFilter;
if (!this.singleObjectId) return null; if (!this.singleObjectId) return null;
if (!filterIdObjects.includes(typeField)) return null; if (!filterIdObjects || !filterIdObjects.includes(typeField)) return null;
return res.replace('=[OBJECT_ID_CONDITION]', ` = ${this.singleObjectId}`); return res.replace('=[OBJECT_ID_CONDITION]', ` = ${this.singleObjectId}`);
} }
if (!this.modifications || !filterIdObjects || this.modifications.length == 0) { if (!this.modifications || !filterIdObjects || this.modifications.length == 0) {
@@ -202,6 +202,9 @@ class MsSqlAnalyser extends DatabaseAnalyser {
const columnsRows = await this.driver.query(this.pool, this.createQuery('columns', ['tables'])); const columnsRows = await this.driver.query(this.pool, this.createQuery('columns', ['tables']));
const pkColumnsRows = await this.driver.query(this.pool, this.createQuery('primaryKeys', ['tables'])); const pkColumnsRows = await this.driver.query(this.pool, this.createQuery('primaryKeys', ['tables']));
const fkColumnsRows = await this.driver.query(this.pool, this.createQuery('foreignKeys', ['tables'])); const fkColumnsRows = await this.driver.query(this.pool, this.createQuery('foreignKeys', ['tables']));
const schemaRows = await this.driver.query(this.pool, this.createQuery('getSchemas'));
const schemas = schemaRows.rows;
const sqlCodeRows = await this.driver.query( const sqlCodeRows = await this.driver.query(
this.pool, this.pool,
@@ -265,6 +268,7 @@ class MsSqlAnalyser extends DatabaseAnalyser {
views, views,
procedures, procedures,
functions, functions,
schemas,
}); });
} }

View File

@@ -0,0 +1 @@
module.exports = `select schema_id as objectId, name as schemaName from sys.schemas`;

View File

@@ -7,6 +7,7 @@ const loadSqlCode = require('./loadSqlCode');
const views = require('./views'); const views = require('./views');
const programmables = require('./programmables'); const programmables = require('./programmables');
const viewColumns = require('./viewColumns'); const viewColumns = require('./viewColumns');
const getSchemas = require('./getSchemas');
module.exports = { module.exports = {
columns, columns,
@@ -18,4 +19,5 @@ module.exports = {
views, views,
programmables, programmables,
viewColumns, viewColumns,
getSchemas,
}; };

View File

@@ -71,10 +71,16 @@ export interface FunctionInfo extends SqlObjectInfo {}
export interface TriggerInfo extends SqlObjectInfo {} export interface TriggerInfo extends SqlObjectInfo {}
export interface SchemaInfo {
objectId?: string;
schemaName: string;
}
export interface DatabaseInfo { export interface DatabaseInfo {
tables: TableInfo[]; tables: TableInfo[];
views: ViewInfo[]; views: ViewInfo[];
procedures: ProcedureInfo[]; procedures: ProcedureInfo[];
functions: FunctionInfo[]; functions: FunctionInfo[];
triggers: TriggerInfo[]; triggers: TriggerInfo[];
schemas: SchemaInfo[];
} }

View File

@@ -114,7 +114,8 @@ function Menu({ data, makeAppObj, setOpenedTabs, showModal }) {
sourceStorageType: 'database', sourceStorageType: 'database',
sourceConnectionId: data.conid, sourceConnectionId: data.conid,
sourceDatabaseName: data.database, sourceDatabaseName: data.database,
sourceTables: [fullNameToString(data)], sourceSchemaName: data.schemaName,
sourceTables: [data.pureName],
}} }}
/> />
)); ));

View File

@@ -604,7 +604,8 @@ export default function DataGridCore(props) {
sourceStorageType: 'database', sourceStorageType: 'database',
sourceConnectionId: conid, sourceConnectionId: conid,
sourceDatabaseName: database, sourceDatabaseName: database,
sourceTables: display.baseTable ? [fullNameToString(display.baseTable)] : [], sourceSchemaName: display.baseTable && display.baseTable.schemaName,
sourceTables: display.baseTable ? [display.baseTable.pureName] : [],
}} }}
/> />
)); ));

View File

@@ -11,9 +11,12 @@ import {
FormConnectionSelect, FormConnectionSelect,
FormDatabaseSelect, FormDatabaseSelect,
FormTablesSelect, FormTablesSelect,
FormSelectField,
FormSchemaSelect,
} from '../utility/forms'; } from '../utility/forms';
import { useConnectionList, useDatabaseList } from '../utility/metadataLoaders'; import { useConnectionList, useDatabaseList } from '../utility/metadataLoaders';
import TableControl, { TableColumn } from '../utility/TableControl'; import TableControl, { TableColumn } from '../utility/TableControl';
import { TextField, SelectField } from '../utility/inputs';
const Container = styled.div``; const Container = styled.div``;
@@ -66,9 +69,9 @@ function DatabaseSelector() {
); );
} }
function SourceTargetConfig({ direction, storageTypeField, connectionIdField, databaseNameField, tablesField }) { function SourceTargetConfig({ direction, storageTypeField, connectionIdField, databaseNameField, schemaNameField,tablesField }) {
const types = [ const types = [
{ value: 'database', label: 'Database', directions: ['source'] }, { value: 'database', label: 'Database', directions: ['source', 'target'] },
{ value: 'csv', label: 'CSV file(s)', directions: ['target'] }, { value: 'csv', label: 'CSV file(s)', directions: ['target'] },
{ value: 'jsonl', label: 'JSON lines file(s)', directions: ['target'] }, { value: 'jsonl', label: 'JSON lines file(s)', directions: ['target'] },
]; ];
@@ -84,10 +87,12 @@ function SourceTargetConfig({ direction, storageTypeField, connectionIdField, da
<FormConnectionSelect name={connectionIdField} /> <FormConnectionSelect name={connectionIdField} />
<Label>Database</Label> <Label>Database</Label>
<FormDatabaseSelect conidName={connectionIdField} name={databaseNameField} /> <FormDatabaseSelect conidName={connectionIdField} name={databaseNameField} />
<Label>Schema</Label>
<FormSchemaSelect conidName={connectionIdField} databaseName={databaseNameField} name={schemaNameField} />
{direction == 'source' && ( {direction == 'source' && (
<> <>
<Label>Tables/views</Label> <Label>Tables/views</Label>
<FormTablesSelect conidName={connectionIdField} databaseName={databaseNameField} name={tablesField} /> <FormTablesSelect conidName={connectionIdField} schemaName={schemaNameField} databaseName={databaseNameField} name={tablesField} />
</> </>
)} )}
</> </>
@@ -99,6 +104,9 @@ function SourceTargetConfig({ direction, storageTypeField, connectionIdField, da
export default function ImportExportConfigurator() { export default function ImportExportConfigurator() {
const { values } = useFormikContext(); const { values } = useFormikContext();
const sources = values.sourceTables; const sources = values.sourceTables;
const getActionOptions = ()=>{
}
const actionOptions = [ const actionOptions = [
{ {
label: 'Create file', label: 'Create file',
@@ -125,6 +133,7 @@ export default function ImportExportConfigurator() {
storageTypeField="sourceStorageType" storageTypeField="sourceStorageType"
connectionIdField="sourceConnectionId" connectionIdField="sourceConnectionId"
databaseNameField="sourceDatabaseName" databaseNameField="sourceDatabaseName"
schemaNameField="sourceSchemaName"
tablesField="sourceTables" tablesField="sourceTables"
/> />
<SourceTargetConfig <SourceTargetConfig
@@ -132,17 +141,15 @@ export default function ImportExportConfigurator() {
storageTypeField="targetStorageType" storageTypeField="targetStorageType"
connectionIdField="targetConnectionId" connectionIdField="targetConnectionId"
databaseNameField="targetDatabaseName" databaseNameField="targetDatabaseName"
schemaNameField="targetSchemaName"
tablesField="targetTables" tablesField="targetTables"
/> />
</Wrapper> </Wrapper>
{/* <TableControl rows={sources || []}> <TableControl rows={sources || []}>
<TableColumn fieldName="source" header="Source" formatter={(row) => row} /> <TableColumn fieldName="source" header="Source" formatter={(row) => row} />
<TableColumn <TableColumn fieldName="action" header="Action" formatter={(row) => <SelectField options={actionOptions} />} />
fieldName="action" <TableColumn fieldName="target" header="Target" formatter={(row) => <TextField />} />
header="Action" </TableControl>
formatter={(row) => <FormReactSelect name={`action_${row}`} options={actionOptions} />}
/>
</TableControl> */}
</Container> </Container>
); );
} }

View File

@@ -14,7 +14,7 @@ export default async function createImpExpScript(values) {
const connection = await getConnectionInfo({ conid: values.sourceConnectionId }); const connection = await getConnectionInfo({ conid: values.sourceConnectionId });
const driver = engines(connection); const driver = engines(connection);
const fullName = fullNameFromString(table); const fullName = { schemaName: values.sourceSchemaName, pureName: table };
script.assign(sourceVar, 'queryReader', { script.assign(sourceVar, 'queryReader', {
connection: { connection: {
..._.pick(connection, ['server', 'engine', 'user', 'password', 'port']), ..._.pick(connection, ['server', 'engine', 'user', 'password', 'port']),

View File

@@ -50,7 +50,7 @@ export function FormSelectFieldRaw({ children, ...other }) {
); );
} }
export function FormSelectField({ label, children, ...other }) { export function FormSelectField({ label, children = null, ...other }) {
return ( return (
<FormRow> <FormRow>
<FormLabel>{label}</FormLabel> <FormLabel>{label}</FormLabel>
@@ -138,16 +138,34 @@ export function FormDatabaseSelect({ conidName, name }) {
return <FormReactSelect options={databaseOptions} name={name} />; return <FormReactSelect options={databaseOptions} name={name} />;
} }
export function FormTablesSelect({ conidName, databaseName, name }) { export function FormSchemaSelect({ conidName, databaseName, name }) {
const { values } = useFormikContext();
const dbinfo = useDatabaseInfo({ conid: values[conidName], database: values[databaseName] });
const schemaOptions = React.useMemo(
() =>
((dbinfo && dbinfo.schemas) || []).map((schema) => ({
value: schema.schemaName,
label: schema.schemaName,
})),
[dbinfo]
);
if (schemaOptions.length == 0) return <div>Not available</div>;
return <FormReactSelect options={schemaOptions} name={name} />;
}
export function FormTablesSelect({ conidName, databaseName, schemaName, name }) {
const { values } = useFormikContext(); const { values } = useFormikContext();
const dbinfo = useDatabaseInfo({ conid: values[conidName], database: values[databaseName] }); const dbinfo = useDatabaseInfo({ conid: values[conidName], database: values[databaseName] });
const tablesOptions = React.useMemo( const tablesOptions = React.useMemo(
() => () =>
[...((dbinfo && dbinfo.tables) || []), ...((dbinfo && dbinfo.views) || [])].map((x) => ({ [...((dbinfo && dbinfo.tables) || []), ...((dbinfo && dbinfo.views) || [])]
value: fullNameToString(x), .filter((x) => !values[schemaName] || x.schemaName == values[schemaName])
label: x.pureName, .map((x) => ({
})), value: x.pureName,
[dbinfo] label: x.pureName,
})),
[dbinfo, values[schemaName]]
); );
if (tablesOptions.length == 0) return <div>Not available</div>; if (tablesOptions.length == 0) return <div>Not available</div>;

View File

@@ -4,6 +4,15 @@ export function TextField({ editorRef = undefined, ...other }) {
return <input type="text" {...other} ref={editorRef}></input>; return <input type="text" {...other} ref={editorRef}></input>;
} }
export function SelectField({ children, ...other }) { export function SelectField({ children = null, options = [], ...other }) {
return <select {...other}>{children}</select>; return (
<select {...other}>
{children}
{options.map((x) => (
<option value={x.value} key={x.value}>
{x.label}
</option>
))}
</select>
);
} }