mirror of
https://github.com/apache/superset.git
synced 2026-04-20 00:24:38 +00:00
chore(command): Organize Commands according to SIP-92 (#25850)
This commit is contained in:
@@ -1,16 +0,0 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
@@ -1,103 +0,0 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
import logging
|
||||
from datetime import datetime
|
||||
from typing import Any, Optional, Union
|
||||
from uuid import UUID
|
||||
|
||||
from sqlalchemy.exc import SQLAlchemyError
|
||||
|
||||
from superset import db
|
||||
from superset.commands.base import BaseCommand
|
||||
from superset.key_value.exceptions import KeyValueCreateFailedError
|
||||
from superset.key_value.models import KeyValueEntry
|
||||
from superset.key_value.types import Key, KeyValueCodec, KeyValueResource
|
||||
from superset.utils.core import get_user_id
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class CreateKeyValueCommand(BaseCommand):
|
||||
resource: KeyValueResource
|
||||
value: Any
|
||||
codec: KeyValueCodec
|
||||
key: Optional[Union[int, UUID]]
|
||||
expires_on: Optional[datetime]
|
||||
|
||||
def __init__( # pylint: disable=too-many-arguments
|
||||
self,
|
||||
resource: KeyValueResource,
|
||||
value: Any,
|
||||
codec: KeyValueCodec,
|
||||
key: Optional[Union[int, UUID]] = None,
|
||||
expires_on: Optional[datetime] = None,
|
||||
):
|
||||
"""
|
||||
Create a new key-value pair
|
||||
|
||||
:param resource: the resource (dashboard, chart etc)
|
||||
:param value: the value to persist in the key-value store
|
||||
:param codec: codec used to encode the value
|
||||
:param key: id of entry (autogenerated if undefined)
|
||||
:param expires_on: entry expiration time
|
||||
:
|
||||
"""
|
||||
self.resource = resource
|
||||
self.value = value
|
||||
self.codec = codec
|
||||
self.key = key
|
||||
self.expires_on = expires_on
|
||||
|
||||
def run(self) -> Key:
|
||||
"""
|
||||
Persist the value
|
||||
|
||||
:return: the key associated with the persisted value
|
||||
|
||||
"""
|
||||
try:
|
||||
return self.create()
|
||||
except SQLAlchemyError as ex:
|
||||
db.session.rollback()
|
||||
raise KeyValueCreateFailedError() from ex
|
||||
|
||||
def validate(self) -> None:
|
||||
pass
|
||||
|
||||
def create(self) -> Key:
|
||||
try:
|
||||
value = self.codec.encode(self.value)
|
||||
except Exception as ex:
|
||||
raise KeyValueCreateFailedError("Unable to encode value") from ex
|
||||
entry = KeyValueEntry(
|
||||
resource=self.resource.value,
|
||||
value=value,
|
||||
created_on=datetime.now(),
|
||||
created_by_fk=get_user_id(),
|
||||
expires_on=self.expires_on,
|
||||
)
|
||||
if self.key is not None:
|
||||
try:
|
||||
if isinstance(self.key, UUID):
|
||||
entry.uuid = self.key
|
||||
else:
|
||||
entry.id = self.key
|
||||
except ValueError as ex:
|
||||
raise KeyValueCreateFailedError() from ex
|
||||
db.session.add(entry)
|
||||
db.session.commit()
|
||||
return Key(id=entry.id, uuid=entry.uuid)
|
||||
@@ -1,64 +0,0 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
import logging
|
||||
from typing import Union
|
||||
from uuid import UUID
|
||||
|
||||
from sqlalchemy.exc import SQLAlchemyError
|
||||
|
||||
from superset import db
|
||||
from superset.commands.base import BaseCommand
|
||||
from superset.key_value.exceptions import KeyValueDeleteFailedError
|
||||
from superset.key_value.models import KeyValueEntry
|
||||
from superset.key_value.types import KeyValueResource
|
||||
from superset.key_value.utils import get_filter
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class DeleteKeyValueCommand(BaseCommand):
|
||||
key: Union[int, UUID]
|
||||
resource: KeyValueResource
|
||||
|
||||
def __init__(self, resource: KeyValueResource, key: Union[int, UUID]):
|
||||
"""
|
||||
Delete a key-value pair
|
||||
|
||||
:param resource: the resource (dashboard, chart etc)
|
||||
:param key: the key to delete
|
||||
:return: was the entry deleted or not
|
||||
"""
|
||||
self.resource = resource
|
||||
self.key = key
|
||||
|
||||
def run(self) -> bool:
|
||||
try:
|
||||
return self.delete()
|
||||
except SQLAlchemyError as ex:
|
||||
db.session.rollback()
|
||||
raise KeyValueDeleteFailedError() from ex
|
||||
|
||||
def validate(self) -> None:
|
||||
pass
|
||||
|
||||
def delete(self) -> bool:
|
||||
filter_ = get_filter(self.resource, self.key)
|
||||
if entry := db.session.query(KeyValueEntry).filter_by(**filter_).first():
|
||||
db.session.delete(entry)
|
||||
db.session.commit()
|
||||
return True
|
||||
return False
|
||||
@@ -1,65 +0,0 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
import logging
|
||||
from datetime import datetime
|
||||
|
||||
from sqlalchemy import and_
|
||||
from sqlalchemy.exc import SQLAlchemyError
|
||||
|
||||
from superset import db
|
||||
from superset.commands.base import BaseCommand
|
||||
from superset.key_value.exceptions import KeyValueDeleteFailedError
|
||||
from superset.key_value.models import KeyValueEntry
|
||||
from superset.key_value.types import KeyValueResource
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class DeleteExpiredKeyValueCommand(BaseCommand):
|
||||
resource: KeyValueResource
|
||||
|
||||
def __init__(self, resource: KeyValueResource):
|
||||
"""
|
||||
Delete all expired key-value pairs
|
||||
|
||||
:param resource: the resource (dashboard, chart etc)
|
||||
:return: was the entry deleted or not
|
||||
"""
|
||||
self.resource = resource
|
||||
|
||||
def run(self) -> None:
|
||||
try:
|
||||
self.delete_expired()
|
||||
except SQLAlchemyError as ex:
|
||||
db.session.rollback()
|
||||
raise KeyValueDeleteFailedError() from ex
|
||||
|
||||
def validate(self) -> None:
|
||||
pass
|
||||
|
||||
def delete_expired(self) -> None:
|
||||
(
|
||||
db.session.query(KeyValueEntry)
|
||||
.filter(
|
||||
and_(
|
||||
KeyValueEntry.resource == self.resource.value,
|
||||
KeyValueEntry.expires_on <= datetime.now(),
|
||||
)
|
||||
)
|
||||
.delete()
|
||||
)
|
||||
db.session.commit()
|
||||
@@ -1,72 +0,0 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import logging
|
||||
from datetime import datetime
|
||||
from typing import Any, Optional, Union
|
||||
from uuid import UUID
|
||||
|
||||
from sqlalchemy.exc import SQLAlchemyError
|
||||
|
||||
from superset import db
|
||||
from superset.commands.base import BaseCommand
|
||||
from superset.key_value.exceptions import KeyValueGetFailedError
|
||||
from superset.key_value.models import KeyValueEntry
|
||||
from superset.key_value.types import KeyValueCodec, KeyValueResource
|
||||
from superset.key_value.utils import get_filter
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class GetKeyValueCommand(BaseCommand):
|
||||
resource: KeyValueResource
|
||||
key: Union[int, UUID]
|
||||
codec: KeyValueCodec
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
resource: KeyValueResource,
|
||||
key: Union[int, UUID],
|
||||
codec: KeyValueCodec,
|
||||
):
|
||||
"""
|
||||
Retrieve a key value entry
|
||||
|
||||
:param resource: the resource (dashboard, chart etc)
|
||||
:param key: the key to retrieve
|
||||
:param codec: codec used to decode the value
|
||||
:return: the value associated with the key if present
|
||||
"""
|
||||
self.resource = resource
|
||||
self.key = key
|
||||
self.codec = codec
|
||||
|
||||
def run(self) -> Any:
|
||||
try:
|
||||
return self.get()
|
||||
except SQLAlchemyError as ex:
|
||||
raise KeyValueGetFailedError() from ex
|
||||
|
||||
def validate(self) -> None:
|
||||
pass
|
||||
|
||||
def get(self) -> Optional[Any]:
|
||||
filter_ = get_filter(self.resource, self.key)
|
||||
entry = db.session.query(KeyValueEntry).filter_by(**filter_).first()
|
||||
if entry and (entry.expires_on is None or entry.expires_on > datetime.now()):
|
||||
return self.codec.decode(entry.value)
|
||||
return None
|
||||
@@ -1,90 +0,0 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import logging
|
||||
from datetime import datetime
|
||||
from typing import Any, Optional, Union
|
||||
from uuid import UUID
|
||||
|
||||
from sqlalchemy.exc import SQLAlchemyError
|
||||
|
||||
from superset import db
|
||||
from superset.commands.base import BaseCommand
|
||||
from superset.key_value.exceptions import KeyValueUpdateFailedError
|
||||
from superset.key_value.models import KeyValueEntry
|
||||
from superset.key_value.types import Key, KeyValueCodec, KeyValueResource
|
||||
from superset.key_value.utils import get_filter
|
||||
from superset.utils.core import get_user_id
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class UpdateKeyValueCommand(BaseCommand):
|
||||
resource: KeyValueResource
|
||||
value: Any
|
||||
codec: KeyValueCodec
|
||||
key: Union[int, UUID]
|
||||
expires_on: Optional[datetime]
|
||||
|
||||
def __init__( # pylint: disable=too-many-arguments
|
||||
self,
|
||||
resource: KeyValueResource,
|
||||
key: Union[int, UUID],
|
||||
value: Any,
|
||||
codec: KeyValueCodec,
|
||||
expires_on: Optional[datetime] = None,
|
||||
):
|
||||
"""
|
||||
Update a key value entry
|
||||
|
||||
:param resource: the resource (dashboard, chart etc)
|
||||
:param key: the key to update
|
||||
:param value: the value to persist in the key-value store
|
||||
:param codec: codec used to encode the value
|
||||
:param expires_on: entry expiration time
|
||||
:return: the key associated with the updated value
|
||||
"""
|
||||
self.resource = resource
|
||||
self.key = key
|
||||
self.value = value
|
||||
self.codec = codec
|
||||
self.expires_on = expires_on
|
||||
|
||||
def run(self) -> Optional[Key]:
|
||||
try:
|
||||
return self.update()
|
||||
except SQLAlchemyError as ex:
|
||||
db.session.rollback()
|
||||
raise KeyValueUpdateFailedError() from ex
|
||||
|
||||
def validate(self) -> None:
|
||||
pass
|
||||
|
||||
def update(self) -> Optional[Key]:
|
||||
filter_ = get_filter(self.resource, self.key)
|
||||
entry: KeyValueEntry = (
|
||||
db.session.query(KeyValueEntry).filter_by(**filter_).first()
|
||||
)
|
||||
if entry:
|
||||
entry.value = self.codec.encode(self.value)
|
||||
entry.expires_on = self.expires_on
|
||||
entry.changed_on = datetime.now()
|
||||
entry.changed_by_fk = get_user_id()
|
||||
db.session.commit()
|
||||
return Key(id=entry.id, uuid=entry.uuid)
|
||||
|
||||
return None
|
||||
@@ -1,100 +0,0 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import logging
|
||||
from datetime import datetime
|
||||
from typing import Any, Optional, Union
|
||||
from uuid import UUID
|
||||
|
||||
from sqlalchemy.exc import SQLAlchemyError
|
||||
|
||||
from superset import db
|
||||
from superset.commands.base import BaseCommand
|
||||
from superset.key_value.commands.create import CreateKeyValueCommand
|
||||
from superset.key_value.exceptions import (
|
||||
KeyValueCreateFailedError,
|
||||
KeyValueUpsertFailedError,
|
||||
)
|
||||
from superset.key_value.models import KeyValueEntry
|
||||
from superset.key_value.types import Key, KeyValueCodec, KeyValueResource
|
||||
from superset.key_value.utils import get_filter
|
||||
from superset.utils.core import get_user_id
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class UpsertKeyValueCommand(BaseCommand):
|
||||
resource: KeyValueResource
|
||||
value: Any
|
||||
key: Union[int, UUID]
|
||||
codec: KeyValueCodec
|
||||
expires_on: Optional[datetime]
|
||||
|
||||
def __init__( # pylint: disable=too-many-arguments
|
||||
self,
|
||||
resource: KeyValueResource,
|
||||
key: Union[int, UUID],
|
||||
value: Any,
|
||||
codec: KeyValueCodec,
|
||||
expires_on: Optional[datetime] = None,
|
||||
):
|
||||
"""
|
||||
Upsert a key value entry
|
||||
|
||||
:param resource: the resource (dashboard, chart etc)
|
||||
:param key: the key to update
|
||||
:param value: the value to persist in the key-value store
|
||||
:param codec: codec used to encode the value
|
||||
:param expires_on: entry expiration time
|
||||
:return: the key associated with the updated value
|
||||
"""
|
||||
self.resource = resource
|
||||
self.key = key
|
||||
self.value = value
|
||||
self.codec = codec
|
||||
self.expires_on = expires_on
|
||||
|
||||
def run(self) -> Key:
|
||||
try:
|
||||
return self.upsert()
|
||||
except (KeyValueCreateFailedError, SQLAlchemyError) as ex:
|
||||
db.session.rollback()
|
||||
raise KeyValueUpsertFailedError() from ex
|
||||
|
||||
def validate(self) -> None:
|
||||
pass
|
||||
|
||||
def upsert(self) -> Key:
|
||||
filter_ = get_filter(self.resource, self.key)
|
||||
entry: KeyValueEntry = (
|
||||
db.session.query(KeyValueEntry).filter_by(**filter_).first()
|
||||
)
|
||||
if entry:
|
||||
entry.value = self.codec.encode(self.value)
|
||||
entry.expires_on = self.expires_on
|
||||
entry.changed_on = datetime.now()
|
||||
entry.changed_by_fk = get_user_id()
|
||||
db.session.commit()
|
||||
return Key(entry.id, entry.uuid)
|
||||
|
||||
return CreateKeyValueCommand(
|
||||
resource=self.resource,
|
||||
value=self.value,
|
||||
codec=self.codec,
|
||||
key=self.key,
|
||||
expires_on=self.expires_on,
|
||||
).run()
|
||||
@@ -28,7 +28,7 @@ CODEC = JsonKeyValueCodec()
|
||||
|
||||
def get_shared_value(key: SharedKey) -> Optional[Any]:
|
||||
# pylint: disable=import-outside-toplevel
|
||||
from superset.key_value.commands.get import GetKeyValueCommand
|
||||
from superset.commands.key_value.get import GetKeyValueCommand
|
||||
|
||||
uuid_key = uuid3(NAMESPACE, key)
|
||||
return GetKeyValueCommand(RESOURCE, key=uuid_key, codec=CODEC).run()
|
||||
@@ -36,7 +36,7 @@ def get_shared_value(key: SharedKey) -> Optional[Any]:
|
||||
|
||||
def set_shared_value(key: SharedKey, value: Any) -> None:
|
||||
# pylint: disable=import-outside-toplevel
|
||||
from superset.key_value.commands.create import CreateKeyValueCommand
|
||||
from superset.commands.key_value.create import CreateKeyValueCommand
|
||||
|
||||
uuid_key = uuid3(NAMESPACE, key)
|
||||
CreateKeyValueCommand(
|
||||
|
||||
Reference in New Issue
Block a user