mirror of https://github.com/apache/superset.git
feat: extra table metadata for Google Sheets (#14775)
* feat: GSheets extra table metadata * Bump version
This commit is contained in:
parent
d4480f5c9a
commit
cbc4aa8dc1
2
setup.py
2
setup.py
|
@ -135,7 +135,7 @@ setup(
|
|||
"exasol": ["sqlalchemy-exasol>=2.1.0, <2.2"],
|
||||
"excel": ["xlrd>=1.2.0, <1.3"],
|
||||
"firebird": ["sqlalchemy-firebird>=0.7.0, <0.8"],
|
||||
"gsheets": ["shillelagh[gsheetsapi]>=0.5, <0.6"],
|
||||
"gsheets": ["shillelagh[gsheetsapi]>=0.7.1, <0.8"],
|
||||
"hana": ["hdbcli==2.4.162", "sqlalchemy_hana==0.4.0"],
|
||||
"hive": ["pyhive[hive]>=0.6.1", "tableschema", "thrift>=0.11.0, <1.0.0"],
|
||||
"impala": ["impyla>0.16.2, <0.17"],
|
||||
|
|
|
@ -44,6 +44,7 @@ interface Table {
|
|||
partitionQuery: string;
|
||||
latest: object[];
|
||||
};
|
||||
metadata?: Record<string, string>;
|
||||
indexes?: object[];
|
||||
selectStar?: string;
|
||||
view?: string;
|
||||
|
@ -91,7 +92,8 @@ const TableElement = ({ table, actions, ...props }: TableElementProps) => {
|
|||
};
|
||||
|
||||
const renderWell = () => {
|
||||
let header;
|
||||
let partitions;
|
||||
let metadata;
|
||||
if (table.partitions) {
|
||||
let partitionQuery;
|
||||
let partitionClipBoard;
|
||||
|
@ -111,18 +113,36 @@ const TableElement = ({ table, actions, ...props }: TableElementProps) => {
|
|||
.map(([key, value]) => `${key}=${value}`)
|
||||
.join('/');
|
||||
|
||||
header = (
|
||||
<Card size="small">
|
||||
<div>
|
||||
<small>
|
||||
{t('latest partition:')} {latest}
|
||||
</small>{' '}
|
||||
{partitionClipBoard}
|
||||
</div>
|
||||
</Card>
|
||||
partitions = (
|
||||
<div>
|
||||
<small>
|
||||
{t('latest partition:')} {latest}
|
||||
</small>{' '}
|
||||
{partitionClipBoard}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return header;
|
||||
|
||||
if (table.metadata) {
|
||||
metadata = Object.entries(table.metadata).map(([key, value]) => (
|
||||
<div>
|
||||
<small>
|
||||
<strong>{key}:</strong> {value}
|
||||
</small>
|
||||
</div>
|
||||
));
|
||||
}
|
||||
|
||||
if (!partitions && !metadata) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Card size="small">
|
||||
{partitions}
|
||||
{metadata}
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
const renderControls = () => {
|
||||
|
|
|
@ -117,6 +117,8 @@ export default function getInitialState({
|
|||
foreignKeys,
|
||||
indexes,
|
||||
dataPreviewQueryId,
|
||||
partitions,
|
||||
metadata,
|
||||
} = tableSchema.description;
|
||||
const table = {
|
||||
dbId: tableSchema.database_id,
|
||||
|
@ -133,6 +135,8 @@ export default function getInitialState({
|
|||
primaryKey,
|
||||
foreignKeys,
|
||||
indexes,
|
||||
partitions,
|
||||
metadata,
|
||||
};
|
||||
tables.push(table);
|
||||
});
|
||||
|
|
|
@ -14,8 +14,10 @@
|
|||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
import json
|
||||
import re
|
||||
from typing import Any, Dict, Optional, Pattern, Tuple
|
||||
from contextlib import closing
|
||||
from typing import Any, Dict, Optional, Pattern, Tuple, TYPE_CHECKING
|
||||
|
||||
from flask_babel import gettext as __
|
||||
from sqlalchemy.engine.url import URL
|
||||
|
@ -24,6 +26,10 @@ from superset import security_manager
|
|||
from superset.db_engine_specs.sqlite import SqliteEngineSpec
|
||||
from superset.errors import SupersetErrorType
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from superset.models.core import Database
|
||||
|
||||
|
||||
SYNTAX_ERROR_REGEX = re.compile('SQLError: near "(?P<server_error>.*?)": syntax error')
|
||||
|
||||
|
||||
|
@ -54,3 +60,20 @@ class GSheetsEngineSpec(SqliteEngineSpec):
|
|||
user = security_manager.find_user(username=username)
|
||||
if user and user.email:
|
||||
url.query["subject"] = user.email
|
||||
|
||||
@classmethod
|
||||
def extra_table_metadata(
|
||||
cls, database: "Database", table_name: str, schema_name: str,
|
||||
) -> Dict[str, Any]:
|
||||
engine = cls.get_engine(database, schema=schema_name)
|
||||
with closing(engine.raw_connection()) as conn:
|
||||
cursor = conn.cursor()
|
||||
cursor.execute(f'SELECT GET_METADATA("{table_name}")')
|
||||
results = cursor.fetchone()[0]
|
||||
|
||||
try:
|
||||
metadata = json.loads(results)
|
||||
except Exception: # pylint: disable=broad-except
|
||||
metadata = {}
|
||||
|
||||
return {"metadata": metadata["extra"]}
|
||||
|
|
Loading…
Reference in New Issue