Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve remove_project, add migration to cleanup condition.checks field #47

Merged
merged 1 commit into from
Dec 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 57 additions & 5 deletions featureflags/graph/actions.py
Original file line number Diff line number Diff line change
Expand Up @@ -504,28 +504,80 @@ async def delete_variable(
@auth_required
@track
async def delete_project(
project_id: str,
project_id: UUID,
*,
conn: SAConnection,
) -> None:
"""Physycally deletes project and its:
* flags
* variables
* conditions
* checks
"""
assert project_id, "Project id is required"

project_uuid = UUID(hex=project_id)
# Delete flag conditions
flags = await conn.execute(
select([Flag.id]).where(Flag.project == project_id)
)
flag_ids = [f.id for f in await flags.fetchall()]

await conn.execute(
Condition.__table__.delete().where(Condition.flag.in_(flag_ids))
)

# Delete flags changelog
await conn.execute(
Changelog.__table__.delete().where(Changelog.flag.in_(flag_ids))
)

# Delete project flags
await conn.execute(
Flag.__table__.delete().where(Flag.project == project_id)
)

# Delete value conditions
values = await conn.execute(
select([Value.id]).where(Value.project == project_id)
)
values_ids = [v.id for v in await values.fetchall()]

await conn.execute(
ValueCondition.__table__.delete().where(
ValueCondition.value.in_(values_ids)
)
)

# Delete value changelog
await conn.execute(
ValueChangelog.__table__.delete().where(
ValueChangelog.value.in_(values_ids)
)
)

# Delete project values
await conn.execute(
Flag.__table__.delete().where(Flag.project == project_id)
)

# Delete project variables
variables = await conn.execute(
select([Variable.id]).where(Project.id == project_uuid)
select([Variable.id]).where(Project.id == project_id)
)
variable_ids = [v.id for v in await variables.fetchall()]

# Delete variable checks
if variable_ids:
await conn.execute(
Check.__table__.delete().where(Check.variable.in_(variable_ids))
)

# Delete variables
await conn.execute(
Variable.__table__.delete().where(Variable.project == project_uuid)
Variable.__table__.delete().where(Variable.project == project_id)
)

# Finally delete project
await conn.execute(
Project.__table__.delete().where(Project.id == project_uuid)
Project.__table__.delete().where(Project.id == project_id)
)
16 changes: 1 addition & 15 deletions featureflags/graph/graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -1187,23 +1187,9 @@ async def delete_project(ctx: dict, options: dict) -> DeleteProjectResult:
async with ctx[GraphContext.DB_ENGINE].acquire() as conn:
project_uuid = UUID(options["id"])

is_flags_exists = await exec_scalar(
ctx[GraphContext.DB_ENGINE],
(select([Flag.id]).where(Flag.project == project_uuid).limit(1)),
)
if is_flags_exists:
return DeleteProjectResult("You need delete all Flags firstly.")

is_values_exists = await exec_scalar(
ctx[GraphContext.DB_ENGINE],
(select([Value.id]).where(Value.project == project_uuid).limit(1)),
)
if is_values_exists:
return DeleteProjectResult("You need delete all Values firstly.")

try:
await actions.delete_project(
options["id"],
project_uuid,
conn=conn,
)
except Exception as e:
Expand Down
3 changes: 1 addition & 2 deletions featureflags/graph/proto_adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,7 @@ def variable(self, obj, value):
obj.variable.Variable = value.ident.hex

def operator(self, obj, value):
if value is not None:
obj.operator = value.to_pb()
obj.operator = value.to_pb()

def value_string(self, obj, value):
if value is not None:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
from alembic import op
from sqlalchemy.sql import text

revision = "2fa54f8b55c1"
down_revision = "a327a3ea7a5f"
branch_labels = None
depends_on = None


def upgrade():
conn = op.get_bind()

conditions = list(conn.execute("SELECT id, checks FROM condition"))
checks = list(conn.execute('SELECT id FROM "check"'))

print("Found conditions: {}".format(len(conditions)))
print("Found checks: {}".format(len(checks)))

check_ids = {check.id for check in checks}

for condition in conditions:
new_checks = {check for check in condition.checks if check in check_ids}
if set(condition.checks) != new_checks:
print(
"Updating condition {} with new checks: before={}, after={}".format(
condition.id, condition.checks, new_checks
)
)

conn.execute(
text("UPDATE condition SET checks = :checks WHERE id = :id"),
{"checks": list(new_checks), "id": condition.id},
)


def downgrade(): ...
21 changes: 1 addition & 20 deletions featureflags/rpc/servicer.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,26 +93,7 @@ async def Exchange(self, stream: Stream) -> None: # noqa: N802
db_engine=self._db_engine,
session=user_session.get(),
)
try:
log.debug(
"Graph result: %r",
result.__idx__,
extra={
"project_name": request.project,
"request_verion": request.version,
"project_version": version,
},
)
populate_result_proto(result, exchange_reply.result)
except: # noqa
log.error(
"Failed to populate result proto",
extra={
"project_name": request.project,
"request_verion": request.version,
"project_version": version,
},
)
populate_result_proto(result, exchange_reply.result)

exchange_reply.version = version

Expand Down
2 changes: 1 addition & 1 deletion lets.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ commands:
depends: [build-dev]
cmd: |
docker-compose run --rm backend \
pdm run python3 -m featureflags alembic -- revision --autogenerate -m
pdm run python3 -m featureflags alembic -- revision --autogenerate -m ${LETS_COMMAND_ARGS}

apply-seeds-dev:
description: Apply seeds to local postgres
Expand Down
Loading