Add specific data type options for new table entry form

including basic FK / relationship support
This commit is contained in:
Lance Edgar 2023-01-16 22:50:51 -06:00
parent 98fa6eea05
commit e4c2336659
2 changed files with 166 additions and 21 deletions

View file

@ -118,7 +118,7 @@
v-slot="props" v-slot="props"
% endif % endif
> >
{{ props.row.data_type }} {{ formatDataType(props.row.data_type) }}
</b-table-column> </b-table-column>
<b-table-column field="nullable" <b-table-column field="nullable"
@ -196,26 +196,89 @@
</b-input> </b-input>
</b-field> </b-field>
<b-field label="Data Type"> <b-field grouped>
<b-input v-model="editingColumnDataType"></b-input>
<b-field label="Data Type">
<b-select v-model="editingColumnDataType">
<option value="String">String</option>
<option value="Boolean">Boolean</option>
<option value="Integer">Integer</option>
<option value="Numeric">Numeric</option>
<option value="Date">Date</option>
<option value="DateTime">DateTime</option>
<option value="Text">Text</option>
<option value="_fk_uuid_">FK/UUID</option>
<option value="_other_">Other</option>
</b-select>
</b-field>
<b-field v-if="editingColumnDataType == 'String'"
label="Length"
:type="{'is-danger': !editingColumnDataTypeLength}"
style="max-width: 6rem;">
<b-input v-model="editingColumnDataTypeLength">
</b-input>
</b-field>
<b-field v-if="editingColumnDataType == 'Numeric'"
label="Precision"
:type="{'is-danger': !editingColumnDataTypePrecision}"
style="max-width: 6rem;">
<b-input v-model="editingColumnDataTypePrecision">
</b-input>
</b-field>
<b-field v-if="editingColumnDataType == 'Numeric'"
label="Scale"
:type="{'is-danger': !editingColumnDataTypeScale}"
style="max-width: 6rem;">
<b-input v-model="editingColumnDataTypeScale">
</b-input>
</b-field>
<b-field v-if="editingColumnDataType == '_fk_uuid_'"
label="Reference Table"
:type="{'is-danger': !editingColumnDataTypeReference}">
<b-select v-model="editingColumnDataTypeReference">
<option v-for="table in existingTables"
:key="table.name"
:value="table.name">
{{ table.name }}
</option>
</b-select>
</b-field>
<b-field v-if="editingColumnDataType == '_other_'"
label="Literal (include parens!)"
:type="{'is-danger': !editingColumnDataTypeLiteral}"
expanded>
<b-input v-model="editingColumnDataTypeLiteral">
</b-input>
</b-field>
</b-field> </b-field>
<b-field grouped> <b-field grouped>
<b-field label="Nullable"> <b-field label="Nullable">
<b-checkbox v-model="editingColumnNullable" <b-checkbox v-model="editingColumnNullable"
native-value="true"> native-value="true">
{{ editingColumnNullable }} {{ editingColumnNullable }}
</b-checkbox> </b-checkbox>
</b-field> </b-field>
<b-field label="Versioned" <b-field label="Versioned"
v-if="tableVersioned"> v-if="tableVersioned">
<b-checkbox v-model="editingColumnVersioned" <b-checkbox v-model="editingColumnVersioned"
native-value="true"> native-value="true">
{{ editingColumnVersioned }} {{ editingColumnVersioned }}
</b-checkbox> </b-checkbox>
</b-field> </b-field>
<b-field v-if="editingColumnDataType == '_fk_uuid_'"
label="Relationship">
<b-input v-model="editingColumnRelationship"></b-input>
</b-field>
</b-field> </b-field>
@ -638,6 +701,8 @@
ThisPageData.activeStep = null ThisPageData.activeStep = null
ThisPageData.alembicBranchOptions = ${json.dumps(branch_name_options)|n} ThisPageData.alembicBranchOptions = ${json.dumps(branch_name_options)|n}
ThisPageData.existingTables = ${json.dumps(existing_tables)|n}
ThisPageData.alembicBranch = ${json.dumps(branch_name)|n} ThisPageData.alembicBranch = ${json.dumps(branch_name)|n}
ThisPageData.tableName = '${rattail_app.get_table_prefix()}_widget' ThisPageData.tableName = '${rattail_app.get_table_prefix()}_widget'
ThisPageData.tableModelName = '${rattail_app.get_class_prefix()}Widget' ThisPageData.tableModelName = '${rattail_app.get_class_prefix()}Widget'
@ -648,7 +713,10 @@
ThisPageData.tableColumns = [{ ThisPageData.tableColumns = [{
name: 'uuid', name: 'uuid',
data_type: 'String(length=32)', data_type: {
type: 'String',
length: 32,
},
nullable: false, nullable: false,
description: "UUID primary key", description: "UUID primary key",
versioned: true, versioned: true,
@ -658,17 +726,29 @@
ThisPageData.editingColumn = null ThisPageData.editingColumn = null
ThisPageData.editingColumnName = null ThisPageData.editingColumnName = null
ThisPageData.editingColumnDataType = null ThisPageData.editingColumnDataType = null
ThisPageData.editingColumnDataTypeLength = null
ThisPageData.editingColumnDataTypePrecision = null
ThisPageData.editingColumnDataTypeScale = null
ThisPageData.editingColumnDataTypeReference = null
ThisPageData.editingColumnDataTypeLiteral = null
ThisPageData.editingColumnNullable = true ThisPageData.editingColumnNullable = true
ThisPageData.editingColumnDescription = null ThisPageData.editingColumnDescription = null
ThisPageData.editingColumnVersioned = true ThisPageData.editingColumnVersioned = true
ThisPageData.editingColumnRelationship = null
ThisPage.methods.tableAddColumn = function() { ThisPage.methods.tableAddColumn = function() {
this.editingColumn = null this.editingColumn = null
this.editingColumnName = null this.editingColumnName = null
this.editingColumnDataType = null this.editingColumnDataType = null
this.editingColumnDataTypeLength = null
this.editingColumnDataTypePrecision = null
this.editingColumnDataTypeScale = null
this.editingColumnDataTypeReference = null
this.editingColumnDataTypeLiteral = null
this.editingColumnNullable = true this.editingColumnNullable = true
this.editingColumnDescription = null this.editingColumnDescription = null
this.editingColumnVersioned = true this.editingColumnVersioned = true
this.editingColumnRelationship = null
this.editingColumnShowDialog = true this.editingColumnShowDialog = true
this.$nextTick(() => { this.$nextTick(() => {
this.$refs.editingColumnName.focus() this.$refs.editingColumnName.focus()
@ -678,16 +758,43 @@
ThisPage.methods.tableEditColumn = function(column) { ThisPage.methods.tableEditColumn = function(column) {
this.editingColumn = column this.editingColumn = column
this.editingColumnName = column.name this.editingColumnName = column.name
this.editingColumnDataType = column.data_type this.editingColumnDataType = column.data_type.type
this.editingColumnDataTypeLength = column.data_type.length
this.editingColumnDataTypePrecision = column.data_type.precision
this.editingColumnDataTypeScale = column.data_type.scale
this.editingColumnDataTypeReference = column.data_type.reference
this.editingColumnDataTypeLiteral = column.data_type.literal
this.editingColumnNullable = column.nullable this.editingColumnNullable = column.nullable
this.editingColumnDescription = column.description this.editingColumnDescription = column.description
this.editingColumnVersioned = column.versioned this.editingColumnVersioned = column.versioned
this.editingColumnRelationship = column.relationship
this.editingColumnShowDialog = true this.editingColumnShowDialog = true
this.$nextTick(() => { this.$nextTick(() => {
this.$refs.editingColumnName.focus() this.$refs.editingColumnName.focus()
}) })
} }
ThisPage.methods.formatDataType = function(dataType) {
if (dataType.type == 'String') {
return `sa.String(length=${'$'}{dataType.length})`
} else if (dataType.type == 'Numeric') {
return `sa.Numeric(precision=${'$'}{dataType.precision}, scale=${'$'}{dataType.scale})`
} else if (dataType.type == '_fk_uuid_') {
return 'sa.String(length=32)'
} else if (dataType.type == '_other_') {
return dataType.literal
} else {
return `sa.${'$'}{dataType.type}()`
}
}
ThisPage.watch.editingColumnDataTypeReference = function(newval, oldval) {
this.editingColumnRelationship = newval
if (newval && !this.editingColumnName) {
this.editingColumnName = `${'$'}{newval}_uuid`
}
}
ThisPage.methods.editingColumnSave = function() { ThisPage.methods.editingColumnSave = function() {
let column let column
if (this.editingColumn) { if (this.editingColumn) {
@ -698,10 +805,24 @@
} }
column.name = this.editingColumnName column.name = this.editingColumnName
column.data_type = this.editingColumnDataType
let dataType = {type: this.editingColumnDataType}
if (dataType.type == 'String') {
dataType.length = this.editingColumnDataTypeLength
} else if (dataType.type == 'Numeric') {
dataType.precision = this.editingColumnDataTypePrecision
dataType.scale = this.editingColumnDataTypeScale
} else if (dataType.type == '_fk_uuid_') {
dataType.reference = this.editingColumnDataTypeReference
} else if (dataType.type == '_other_') {
dataType.literal = this.editingColumnDataTypeLiteral
}
column.data_type = dataType
column.nullable = this.editingColumnNullable column.nullable = this.editingColumnNullable
column.description = this.editingColumnDescription column.description = this.editingColumnDescription
column.versioned = this.editingColumnVersioned column.versioned = this.editingColumnVersioned
column.relationship = this.editingColumnRelationship
this.editingColumnShowDialog = false this.editingColumnShowDialog = false
} }
@ -724,6 +845,10 @@
this.modelImportStatus = "import not yet attempted" this.modelImportStatus = "import not yet attempted"
this.modelImportProblem = false this.modelImportProblem = false
for (let column of this.tableColumns) {
column.formatted_data_type = this.formatDataType(column.data_type)
}
let url = '${url('{}.write_model_file'.format(route_prefix))}' let url = '${url('{}.write_model_file'.format(route_prefix))}'
let params = { let params = {
branch_name: this.alembicBranch, branch_name: this.alembicBranch,

View file

@ -31,6 +31,7 @@ import sys
import warnings import warnings
import six import six
from sqlalchemy_utils import get_mapper
from rattail.util import simple_error from rattail.util import simple_error
@ -122,8 +123,6 @@ class TableView(MasterView):
f.remove('versioned') f.remove('versioned')
def get_instance(self): def get_instance(self):
from sqlalchemy_utils import get_mapper
model = self.model model = self.model
table_name = self.request.matchdict['table_name'] table_name = self.request.matchdict['table_name']
@ -204,6 +203,9 @@ class TableView(MasterView):
branch_name = None branch_name = None
kwargs['branch_name'] = branch_name kwargs['branch_name'] = branch_name
kwargs['existing_tables'] = [{'name': table.name}
for table in model.Base.metadata.sorted_tables]
kwargs['model_dir'] = (os.path.dirname(model.__file__) kwargs['model_dir'] = (os.path.dirname(model.__file__)
+ os.sep) + os.sep)
@ -212,6 +214,7 @@ class TableView(MasterView):
def write_model_file(self): def write_model_file(self):
data = self.request.json_body data = self.request.json_body
path = data['module_file'] path = data['module_file']
model = self.model
if os.path.exists(path): if os.path.exists(path):
if data['overwrite']: if data['overwrite']:
@ -219,6 +222,23 @@ class TableView(MasterView):
else: else:
return {'error': "File already exists"} return {'error': "File already exists"}
for column in data['columns']:
if column['data_type']['type'] == '_fk_uuid_' and column['relationship']:
name = column['relationship']
table = model.Base.metadata.tables[column['data_type']['reference']]
try:
mapper = get_mapper(table)
except ValueError:
reference_model = table.name.capitalize()
else:
reference_model = mapper.class_.__name__
column['relationship'] = {
'name': name,
'reference_model': reference_model,
}
self.db_handler.write_table_model(data, path) self.db_handler.write_table_model(data, path)
return {'ok': True} return {'ok': True}