fix(module-key): make module keys standalone MD format with system_key relation
This commit is contained in:
@@ -29,10 +29,17 @@ def _resolve_module_id(db: Session, system_key: str, module_key: str | None) ->
|
|||||||
if not system:
|
if not system:
|
||||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="system_not_found")
|
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="system_not_found")
|
||||||
|
|
||||||
target_module_key = f"{system_key}.{module_key}" if module_key else f"{system_key}.__system__"
|
target_module_key = module_key if module_key else f"__system__{system_key}"
|
||||||
module = modules_repo.get_by_key(target_module_key)
|
module = modules_repo.get_by_key(target_module_key)
|
||||||
|
if module and module.system_key != system_key:
|
||||||
|
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="module_system_mismatch")
|
||||||
if not module:
|
if not module:
|
||||||
module = modules_repo.create(module_key=target_module_key, name=target_module_key, status="active")
|
module = modules_repo.create(
|
||||||
|
module_key=target_module_key,
|
||||||
|
system_key=system_key,
|
||||||
|
name=target_module_key,
|
||||||
|
status="active",
|
||||||
|
)
|
||||||
return module.id
|
return module.id
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -51,10 +51,17 @@ def _resolve_module_id(db: Session, system_key: str, module_key: str | None) ->
|
|||||||
system = systems_repo.get_by_key(system_key)
|
system = systems_repo.get_by_key(system_key)
|
||||||
if not system:
|
if not system:
|
||||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="system_not_found")
|
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="system_not_found")
|
||||||
target_module_key = f"{system_key}.{module_key}" if module_key else f"{system_key}.__system__"
|
target_module_key = module_key if module_key else f"__system__{system_key}"
|
||||||
module = modules_repo.get_by_key(target_module_key)
|
module = modules_repo.get_by_key(target_module_key)
|
||||||
|
if module and module.system_key != system_key:
|
||||||
|
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="module_system_mismatch")
|
||||||
if not module:
|
if not module:
|
||||||
module = modules_repo.create(module_key=target_module_key, name=target_module_key, status="active")
|
module = modules_repo.create(
|
||||||
|
module_key=target_module_key,
|
||||||
|
system_key=system_key,
|
||||||
|
name=target_module_key,
|
||||||
|
status="active",
|
||||||
|
)
|
||||||
return module.id
|
return module.id
|
||||||
|
|
||||||
|
|
||||||
@@ -77,8 +84,6 @@ def _resolve_scope_ids(db: Session, scope_type: str, scope_id: str) -> tuple[str
|
|||||||
def _split_module_key(payload_module: str | None) -> str:
|
def _split_module_key(payload_module: str | None) -> str:
|
||||||
if not payload_module:
|
if not payload_module:
|
||||||
return "__system__"
|
return "__system__"
|
||||||
if "." in payload_module:
|
|
||||||
return payload_module.split(".", 1)[1]
|
|
||||||
return payload_module
|
return payload_module
|
||||||
|
|
||||||
|
|
||||||
@@ -164,11 +169,12 @@ def list_modules(
|
|||||||
items, total = modules_repo.list(limit=limit, offset=offset)
|
items, total = modules_repo.list(limit=limit, offset=offset)
|
||||||
out = []
|
out = []
|
||||||
for i in items:
|
for i in items:
|
||||||
system_key = i.module_key.split(".", 1)[0] if "." in i.module_key else None
|
if i.module_key.startswith("__system__"):
|
||||||
|
continue
|
||||||
out.append(
|
out.append(
|
||||||
ModuleItem(
|
ModuleItem(
|
||||||
id=i.id,
|
id=i.id,
|
||||||
system_key=system_key,
|
system_key=i.system_key,
|
||||||
module_key=i.module_key,
|
module_key=i.module_key,
|
||||||
name=i.name,
|
name=i.name,
|
||||||
status=i.status,
|
status=i.status,
|
||||||
@@ -188,14 +194,14 @@ def create_module(
|
|||||||
system = systems_repo.get_by_key(payload.system_key)
|
system = systems_repo.get_by_key(payload.system_key)
|
||||||
if not system:
|
if not system:
|
||||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="system_not_found")
|
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="system_not_found")
|
||||||
leaf_module_key = _generate_unique_key("MD", lambda k: modules_repo.get_by_key(f"{payload.system_key}.{k}"))
|
leaf_module_key = _generate_unique_key("MD", modules_repo.get_by_key)
|
||||||
full_module_key = f"{payload.system_key}.{leaf_module_key}"
|
|
||||||
row = modules_repo.create(
|
row = modules_repo.create(
|
||||||
module_key=full_module_key,
|
module_key=leaf_module_key,
|
||||||
|
system_key=payload.system_key,
|
||||||
name=payload.name,
|
name=payload.name,
|
||||||
status=payload.status,
|
status=payload.status,
|
||||||
)
|
)
|
||||||
return ModuleItem(id=row.id, system_key=payload.system_key, module_key=row.module_key, name=row.name, status=row.status)
|
return ModuleItem(id=row.id, system_key=row.system_key, module_key=row.module_key, name=row.name, status=row.status)
|
||||||
|
|
||||||
|
|
||||||
@router.patch("/modules/{module_key}")
|
@router.patch("/modules/{module_key}")
|
||||||
@@ -210,8 +216,7 @@ def update_module(
|
|||||||
if not row:
|
if not row:
|
||||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="module_not_found")
|
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="module_not_found")
|
||||||
row = modules_repo.update(row, name=payload.name, status=payload.status)
|
row = modules_repo.update(row, name=payload.name, status=payload.status)
|
||||||
system_key = row.module_key.split(".", 1)[0] if "." in row.module_key else None
|
return ModuleItem(id=row.id, system_key=row.system_key, module_key=row.module_key, name=row.name, status=row.status)
|
||||||
return ModuleItem(id=row.id, system_key=system_key, module_key=row.module_key, name=row.name, status=row.status)
|
|
||||||
|
|
||||||
|
|
||||||
@router.get("/systems/{system_key}/groups")
|
@router.get("/systems/{system_key}/groups")
|
||||||
@@ -268,8 +273,7 @@ def list_module_groups(
|
|||||||
module = modules_repo.get_by_key(module_key)
|
module = modules_repo.get_by_key(module_key)
|
||||||
if not module:
|
if not module:
|
||||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="module_not_found")
|
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="module_not_found")
|
||||||
system_key, module_name = module.module_key.split(".", 1) if "." in module.module_key else ("", module.module_key)
|
groups = groups_repo.list_module_groups(module.system_key, module.module_key)
|
||||||
groups = groups_repo.list_module_groups(system_key, module_name)
|
|
||||||
return {
|
return {
|
||||||
"items": [
|
"items": [
|
||||||
GroupRelationItem(group_key=g.group_key, group_name=g.name, status=g.status).model_dump()
|
GroupRelationItem(group_key=g.group_key, group_name=g.name, status=g.status).model_dump()
|
||||||
@@ -289,8 +293,7 @@ def list_module_members(
|
|||||||
module = modules_repo.get_by_key(module_key)
|
module = modules_repo.get_by_key(module_key)
|
||||||
if not module:
|
if not module:
|
||||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="module_not_found")
|
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="module_not_found")
|
||||||
system_key, module_name = module.module_key.split(".", 1) if "." in module.module_key else ("", module.module_key)
|
members = groups_repo.list_module_members(module.system_key, module.module_key)
|
||||||
members = groups_repo.list_module_members(system_key, module_name)
|
|
||||||
return {
|
return {
|
||||||
"items": [
|
"items": [
|
||||||
MemberRelationItem(
|
MemberRelationItem(
|
||||||
@@ -614,7 +617,7 @@ def list_permission_group_permissions(
|
|||||||
PermissionGroupPermissionItem(
|
PermissionGroupPermissionItem(
|
||||||
id=r.id,
|
id=r.id,
|
||||||
system=r.system,
|
system=r.system,
|
||||||
module=("" if r.module == "__system__" else (r.module if "." in r.module else f"{r.system}.{r.module}")),
|
module="" if r.module == "__system__" else r.module,
|
||||||
action=r.action,
|
action=r.action,
|
||||||
scope_type=r.scope_type,
|
scope_type=r.scope_type,
|
||||||
scope_id=r.scope_id,
|
scope_id=r.scope_id,
|
||||||
@@ -636,7 +639,14 @@ def get_permission_group_bindings(
|
|||||||
if not group:
|
if not group:
|
||||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="group_not_found")
|
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="group_not_found")
|
||||||
snapshot = repo.get_group_binding_snapshot(group.id, group_key)
|
snapshot = repo.get_group_binding_snapshot(group.id, group_key)
|
||||||
return GroupBindingSnapshot(**snapshot)
|
return GroupBindingSnapshot(
|
||||||
|
group_key=snapshot["group_key"],
|
||||||
|
site_keys=snapshot["site_keys"],
|
||||||
|
system_keys=snapshot["system_keys"],
|
||||||
|
module_keys=[k.split("|", 1)[1] if "|" in k else k for k in snapshot["module_keys"]],
|
||||||
|
member_subs=snapshot["member_subs"],
|
||||||
|
actions=snapshot["actions"],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@router.put("/permission-groups/{group_key}/bindings", response_model=GroupBindingSnapshot)
|
@router.put("/permission-groups/{group_key}/bindings", response_model=GroupBindingSnapshot)
|
||||||
@@ -669,21 +679,32 @@ def replace_permission_group_bindings(
|
|||||||
if missing_systems:
|
if missing_systems:
|
||||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"system_not_found:{','.join(missing_systems)}")
|
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"system_not_found:{','.join(missing_systems)}")
|
||||||
|
|
||||||
valid_modules = {m.module_key for m in modules_repo.list(limit=10000, offset=0)[0]}
|
all_modules = modules_repo.list(limit=10000, offset=0)[0]
|
||||||
|
valid_modules = {m.module_key for m in all_modules}
|
||||||
|
module_system_lookup = {m.module_key: m.system_key for m in all_modules}
|
||||||
missing_modules = [k for k in module_keys if k not in valid_modules]
|
missing_modules = [k for k in module_keys if k not in valid_modules]
|
||||||
if missing_modules:
|
if missing_modules:
|
||||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"module_not_found:{','.join(missing_modules)}")
|
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"module_not_found:{','.join(missing_modules)}")
|
||||||
|
|
||||||
|
module_pairs = [f"{module_system_lookup[m]}|{m}" for m in module_keys]
|
||||||
|
|
||||||
repo.replace_group_bindings(
|
repo.replace_group_bindings(
|
||||||
group_id=group.id,
|
group_id=group.id,
|
||||||
site_keys=site_keys,
|
site_keys=site_keys,
|
||||||
system_keys=system_keys,
|
system_keys=system_keys,
|
||||||
module_keys=module_keys,
|
module_keys=module_pairs,
|
||||||
member_subs=payload.member_subs,
|
member_subs=payload.member_subs,
|
||||||
actions=payload.actions,
|
actions=payload.actions,
|
||||||
)
|
)
|
||||||
snapshot = repo.get_group_binding_snapshot(group.id, group_key)
|
snapshot = repo.get_group_binding_snapshot(group.id, group_key)
|
||||||
return GroupBindingSnapshot(**snapshot)
|
return GroupBindingSnapshot(
|
||||||
|
group_key=snapshot["group_key"],
|
||||||
|
site_keys=snapshot["site_keys"],
|
||||||
|
system_keys=snapshot["system_keys"],
|
||||||
|
module_keys=[k.split("|", 1)[1] if "|" in k else k for k in snapshot["module_keys"]],
|
||||||
|
member_subs=snapshot["member_subs"],
|
||||||
|
actions=snapshot["actions"],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@router.post("/permission-groups", response_model=PermissionGroupItem)
|
@router.post("/permission-groups", response_model=PermissionGroupItem)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from uuid import uuid4
|
from uuid import uuid4
|
||||||
|
|
||||||
from sqlalchemy import DateTime, String, func
|
from sqlalchemy import DateTime, ForeignKey, String, func
|
||||||
from sqlalchemy.dialects.postgresql import UUID
|
from sqlalchemy.dialects.postgresql import UUID
|
||||||
from sqlalchemy.orm import Mapped, mapped_column
|
from sqlalchemy.orm import Mapped, mapped_column
|
||||||
|
|
||||||
@@ -12,6 +12,9 @@ class Module(Base):
|
|||||||
__tablename__ = "modules"
|
__tablename__ = "modules"
|
||||||
|
|
||||||
id: Mapped[str] = mapped_column(UUID(as_uuid=False), primary_key=True, default=lambda: str(uuid4()))
|
id: Mapped[str] = mapped_column(UUID(as_uuid=False), primary_key=True, default=lambda: str(uuid4()))
|
||||||
|
system_key: Mapped[str] = mapped_column(
|
||||||
|
String(128), ForeignKey("systems.system_key", ondelete="CASCADE"), nullable=False, index=True
|
||||||
|
)
|
||||||
module_key: Mapped[str] = mapped_column(String(128), unique=True, nullable=False, index=True)
|
module_key: Mapped[str] = mapped_column(String(128), unique=True, nullable=False, index=True)
|
||||||
name: Mapped[str] = mapped_column(String(255), nullable=False)
|
name: Mapped[str] = mapped_column(String(255), nullable=False)
|
||||||
status: Mapped[str] = mapped_column(String(16), nullable=False, default="active")
|
status: Mapped[str] = mapped_column(String(16), nullable=False, default="active")
|
||||||
|
|||||||
@@ -18,8 +18,8 @@ class ModulesRepository:
|
|||||||
stmt = stmt.order_by(Module.created_at.desc()).limit(limit).offset(offset)
|
stmt = stmt.order_by(Module.created_at.desc()).limit(limit).offset(offset)
|
||||||
return list(self.db.scalars(stmt).all()), int(self.db.scalar(count_stmt) or 0)
|
return list(self.db.scalars(stmt).all()), int(self.db.scalar(count_stmt) or 0)
|
||||||
|
|
||||||
def create(self, module_key: str, name: str, status: str = "active") -> Module:
|
def create(self, module_key: str, system_key: str, name: str, status: str = "active") -> Module:
|
||||||
item = Module(module_key=module_key, name=name, status=status)
|
item = Module(module_key=module_key, system_key=system_key, name=name, status=status)
|
||||||
self.db.add(item)
|
self.db.add(item)
|
||||||
self.db.commit()
|
self.db.commit()
|
||||||
self.db.refresh(item)
|
self.db.refresh(item)
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from collections import defaultdict
|
|
||||||
|
|
||||||
from sqlalchemy import delete, func, select
|
from sqlalchemy import delete, func, select
|
||||||
from sqlalchemy.orm import Session
|
from sqlalchemy.orm import Session
|
||||||
|
|
||||||
@@ -142,17 +140,16 @@ class PermissionGroupsRepository:
|
|||||||
normalized_actions = [a for a in list(dict.fromkeys(actions)) if a in {"view", "edit"}]
|
normalized_actions = [a for a in list(dict.fromkeys(actions)) if a in {"view", "edit"}]
|
||||||
normalized_member_subs = list(dict.fromkeys([s for s in member_subs if s]))
|
normalized_member_subs = list(dict.fromkeys([s for s in member_subs if s]))
|
||||||
|
|
||||||
modules_by_system: dict[str, list[str]] = defaultdict(list)
|
|
||||||
for full_module_key in list(dict.fromkeys([m for m in module_keys if m])):
|
|
||||||
if "." not in full_module_key:
|
|
||||||
continue
|
|
||||||
system_key, module_name = full_module_key.split(".", 1)
|
|
||||||
if module_name == "__system__":
|
|
||||||
continue
|
|
||||||
modules_by_system[system_key].append(module_name)
|
|
||||||
|
|
||||||
normalized_systems = set([s for s in system_keys if s])
|
normalized_systems = set([s for s in system_keys if s])
|
||||||
normalized_systems.update(modules_by_system.keys())
|
module_pairs = []
|
||||||
|
for pair in module_keys:
|
||||||
|
if "|" not in pair:
|
||||||
|
continue
|
||||||
|
system_key, module_key = pair.split("|", 1)
|
||||||
|
if not system_key or not module_key:
|
||||||
|
continue
|
||||||
|
module_pairs.append((system_key, module_key))
|
||||||
|
normalized_systems.add(system_key)
|
||||||
|
|
||||||
self.db.execute(delete(PermissionGroupPermission).where(PermissionGroupPermission.group_id == group_id))
|
self.db.execute(delete(PermissionGroupPermission).where(PermissionGroupPermission.group_id == group_id))
|
||||||
self.db.execute(delete(PermissionGroupMember).where(PermissionGroupMember.group_id == group_id))
|
self.db.execute(delete(PermissionGroupMember).where(PermissionGroupMember.group_id == group_id))
|
||||||
@@ -163,7 +160,7 @@ class PermissionGroupsRepository:
|
|||||||
for site_key in normalized_sites:
|
for site_key in normalized_sites:
|
||||||
for action in normalized_actions:
|
for action in normalized_actions:
|
||||||
for system_key in sorted(normalized_systems):
|
for system_key in sorted(normalized_systems):
|
||||||
module_names = modules_by_system.get(system_key) or ["__system__"]
|
module_names = [m for s, m in module_pairs if s == system_key] or ["__system__"]
|
||||||
for module_name in module_names:
|
for module_name in module_names:
|
||||||
self.db.add(
|
self.db.add(
|
||||||
PermissionGroupPermission(
|
PermissionGroupPermission(
|
||||||
@@ -185,7 +182,7 @@ class PermissionGroupsRepository:
|
|||||||
actions = sorted({p.action for p in permissions if p.action in {"view", "edit"}})
|
actions = sorted({p.action for p in permissions if p.action in {"view", "edit"}})
|
||||||
module_keys = sorted(
|
module_keys = sorted(
|
||||||
{
|
{
|
||||||
p.module if "." in p.module else f"{p.system}.{p.module}"
|
f"{p.system}|{p.module}"
|
||||||
for p in permissions
|
for p in permissions
|
||||||
if p.module and p.module != "__system__"
|
if p.module and p.module != "__system__"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ class PermissionsRepository:
|
|||||||
UserScopePermission.scope_type,
|
UserScopePermission.scope_type,
|
||||||
Company.company_key,
|
Company.company_key,
|
||||||
Site.site_key,
|
Site.site_key,
|
||||||
|
Module.system_key,
|
||||||
Module.module_key,
|
Module.module_key,
|
||||||
UserScopePermission.action,
|
UserScopePermission.action,
|
||||||
)
|
)
|
||||||
@@ -55,13 +56,10 @@ class PermissionsRepository:
|
|||||||
if source == "group":
|
if source == "group":
|
||||||
_, scope_type, scope_id, system_key, module_key, action = row
|
_, scope_type, scope_id, system_key, module_key, action = row
|
||||||
if module_key == "__system__":
|
if module_key == "__system__":
|
||||||
module_key = f"{system_key}.__system__"
|
module_key = f"__system__{system_key}"
|
||||||
elif module_key and "." not in module_key:
|
|
||||||
module_key = f"{system_key}.{module_key}"
|
|
||||||
else:
|
else:
|
||||||
_, scope_type, company_key, site_key, module_key, action = row
|
_, scope_type, company_key, site_key, system_key, module_key, action = row
|
||||||
scope_id = company_key if scope_type == "company" else site_key
|
scope_id = company_key if scope_type == "company" else site_key
|
||||||
system_key = module_key.split(".", 1)[0] if isinstance(module_key, str) and "." in module_key else None
|
|
||||||
key = (scope_type, scope_id or "", system_key, module_key, action)
|
key = (scope_type, scope_id or "", system_key, module_key, action)
|
||||||
if key in dedup:
|
if key in dedup:
|
||||||
continue
|
continue
|
||||||
@@ -146,6 +144,7 @@ class PermissionsRepository:
|
|||||||
UserScopePermission.scope_type,
|
UserScopePermission.scope_type,
|
||||||
Company.company_key,
|
Company.company_key,
|
||||||
Site.site_key,
|
Site.site_key,
|
||||||
|
Module.system_key,
|
||||||
Module.module_key,
|
Module.module_key,
|
||||||
UserScopePermission.action,
|
UserScopePermission.action,
|
||||||
UserScopePermission.created_at,
|
UserScopePermission.created_at,
|
||||||
@@ -200,14 +199,14 @@ class PermissionsRepository:
|
|||||||
row_scope_type,
|
row_scope_type,
|
||||||
company_key,
|
company_key,
|
||||||
site_key,
|
site_key,
|
||||||
|
system_key,
|
||||||
module_key,
|
module_key,
|
||||||
action,
|
action,
|
||||||
created_at,
|
created_at,
|
||||||
) = row
|
) = row
|
||||||
scope_id = company_key if row_scope_type == "company" else site_key
|
scope_id = company_key if row_scope_type == "company" else site_key
|
||||||
system_key = module_key.split(".", 1)[0] if isinstance(module_key, str) and "." in module_key else None
|
module_name = module_key
|
||||||
module_name = module_key.split(".", 1)[1] if isinstance(module_key, str) and "." in module_key else module_key
|
if isinstance(module_name, str) and module_name.startswith("__system__"):
|
||||||
if module_name == "__system__":
|
|
||||||
module_name = None
|
module_name = None
|
||||||
items.append(
|
items.append(
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -67,6 +67,7 @@ CREATE TABLE systems (
|
|||||||
|
|
||||||
CREATE TABLE modules (
|
CREATE TABLE modules (
|
||||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||||
|
system_key TEXT NOT NULL REFERENCES systems(system_key) ON DELETE CASCADE,
|
||||||
module_key TEXT NOT NULL UNIQUE,
|
module_key TEXT NOT NULL UNIQUE,
|
||||||
name TEXT NOT NULL,
|
name TEXT NOT NULL,
|
||||||
status VARCHAR(16) NOT NULL DEFAULT 'active',
|
status VARCHAR(16) NOT NULL DEFAULT 'active',
|
||||||
@@ -156,6 +157,7 @@ CREATE INDEX idx_pgp_scope_site ON permission_group_permissions(scope_id);
|
|||||||
CREATE INDEX idx_api_clients_status ON api_clients(status);
|
CREATE INDEX idx_api_clients_status ON api_clients(status);
|
||||||
CREATE INDEX idx_api_clients_expires_at ON api_clients(expires_at);
|
CREATE INDEX idx_api_clients_expires_at ON api_clients(expires_at);
|
||||||
CREATE INDEX idx_systems_system_key ON systems(system_key);
|
CREATE INDEX idx_systems_system_key ON systems(system_key);
|
||||||
|
CREATE INDEX idx_modules_system_key ON modules(system_key);
|
||||||
CREATE INDEX idx_modules_module_key ON modules(module_key);
|
CREATE INDEX idx_modules_module_key ON modules(module_key);
|
||||||
|
|
||||||
COMMIT;
|
COMMIT;
|
||||||
|
|||||||
Reference in New Issue
Block a user