Skip to content

Commit 71921bd

Browse files
committed
feat(logic): delete fields;
- Added delete_fields to recombinant update logic aciton method.
1 parent 66e8678 commit 71921bd

File tree

5 files changed

+46
-24
lines changed

5 files changed

+46
-24
lines changed

changes/140.changes

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
`recombinant_update` with `force` will now DROP old columns from the DataStore for fields that do not exist in the Schema.
1+
`recombinant_update` with `force` and `delete_fields` will now DROP old columns from the DataStore for fields that do not exist in the Schema.

ckanext/recombinant/cli.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -116,19 +116,26 @@ def remove_empty(dataset_type: Optional[List[str]] = None,
116116
is_flag=True,
117117
help="Force update of tables (required for changes to only primary keys/indexes)",
118118
)
119+
@click.option(
120+
"-d",
121+
"--delete-fields",
122+
is_flag=True,
123+
help="Deletes fields that are no longer in the Schema (requires --force-update)",
124+
)
119125
@click.option('-v', '--verbose', is_flag=True,
120126
type=click.BOOL, help='Increase verbosity.')
121127
def update(dataset_type: Optional[List[str]] = None,
122128
all_types: bool = False,
123129
force_update: bool = False,
130+
delete_fields: bool = False,
124131
verbose: bool = False):
125132
"""
126133
Triggers recombinant update for recombinant resources
127134
128135
Full Usage:\n
129136
recombinant update (-a | DATASET_TYPE ...) [-f]
130137
"""
131-
_update(dataset_type, all_types, force_update, verbose=verbose)
138+
_update(dataset_type, all_types, force_update, delete_fields, verbose=verbose)
132139

133140

134141
@recombinant.command(short_help="Delete recombinant datasets and all their data.")
@@ -349,6 +356,7 @@ def _show(dataset_type: Optional[str],
349356
def _update(dataset_types: Optional[List[str]],
350357
all_types: bool = False,
351358
force_update: bool = False,
359+
delete_fields: bool = False,
352360
verbose: bool = False):
353361
"""
354362
Triggers recombinant update for recombinant resources
@@ -366,7 +374,8 @@ def _update(dataset_types: Optional[List[str]],
366374
click.echo('%s %s updating' % (dtype, o))
367375
lc.action.recombinant_update(
368376
owner_org=o, dataset_type=dtype,
369-
force_update=force_update)
377+
force_update=force_update,
378+
delete_fields=delete_fields)
370379

371380

372381
def _expand_dataset_types(dataset_types: Optional[List[str]],

ckanext/recombinant/logic.py

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ def recombinant_update(context: Context, data_dict: DataDict):
6262
:param owner_org: organization name or id
6363
:param delete_resources: True to delete extra resources found
6464
:param force_update: True to force updating of datastore tables
65+
:param delete_fields: True to delete old fields not in schema,
66+
requires force_update=True
6567
'''
6668
lc, geno, dataset = _action_get_dataset(context, data_dict)
6769

@@ -70,7 +72,8 @@ def recombinant_update(context: Context, data_dict: DataDict):
7072
delete_resources=asbool(data_dict.get('delete_resources', False)))
7173
_update_datastore(
7274
lc, geno, dataset,
73-
force_update=asbool(data_dict.get('force_update', False)))
75+
force_update=asbool(data_dict.get('force_update', False)),
76+
delete_fields=asbool(data_dict.get('delete_fields', False)))
7477

7578

7679
def recombinant_show(context: Context, data_dict: DataDict) -> Dict[str, Any]:
@@ -245,7 +248,8 @@ def _update_dataset(lc: LocalCKAN,
245248
def _update_datastore(lc: LocalCKAN,
246249
geno: Dict[str, Any],
247250
dataset: Dict[str, Any],
248-
force_update: bool = False):
251+
force_update: bool = False,
252+
delete_fields: bool = False):
249253
"""
250254
call lc.action.datastore_create to create tables or add
251255
columns to existing datastore tables based on dataset definition
@@ -260,7 +264,7 @@ def _update_datastore(lc: LocalCKAN,
260264
chromo['resource_name'], dataset['id'])
261265
resource_id = resource_ids[chromo['resource_name']]
262266
fields = datastore_fields(chromo['fields'], datastore_text_types)
263-
delete_fields = False
267+
do_delete_fields = False
264268
try:
265269
ds = lc.action.datastore_search(resource_id=resource_id, limit=0)
266270
except NotFound:
@@ -275,17 +279,18 @@ def _update_datastore(lc: LocalCKAN,
275279
for f in datastore_fields(chromo['fields'], datastore_text_types):
276280
if f['id'] not in seen:
277281
fields.append(f)
278-
# remove any fields from DS not in Schema
279-
new_fields = []
280-
schema_field_ids = set(
281-
f['id'] for f in datastore_fields(chromo['fields'],
282-
datastore_text_types))
283-
for f in fields:
284-
if f['id'] not in schema_field_ids:
285-
delete_fields = True
286-
continue
287-
new_fields.append(f)
288-
fields = new_fields
282+
if delete_fields:
283+
# remove any fields from DS not in Schema
284+
new_fields = []
285+
schema_field_ids = set(
286+
f['id'] for f in datastore_fields(chromo['fields'],
287+
datastore_text_types))
288+
for f in fields:
289+
if f['id'] not in schema_field_ids:
290+
do_delete_fields = True
291+
continue
292+
new_fields.append(f)
293+
fields = new_fields
289294

290295
trigger_names = _update_triggers(lc, chromo)
291296

@@ -305,7 +310,7 @@ def _update_datastore(lc: LocalCKAN,
305310
lc.action.datastore_create(
306311
resource_id=resource_id,
307312
fields=fields,
308-
delete_fields=delete_fields,
313+
delete_fields=do_delete_fields,
309314
primary_key=chromo.get('datastore_primary_key', []),
310315
foreign_keys=foreign_keys,
311316
indexes=chromo.get('datastore_indexes', []),

ckanext/recombinant/templates/recombinant/resource_edit.html

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,13 +45,14 @@
4545
{% block action_panels %}
4646
{% if dataset %}
4747
{% if 'error' not in resource %}
48-
{% if not resource.datastore_correct %}
48+
{% if g.userobj.sysadmin and not resource.datastore_correct %}
49+
{# only let sysadmins refresh the recombinant record via UI #}
4950
<div class="module-alert alert alert-warning">
50-
<h3>{{ _("The Recombinant resource is out of date") }}</h3>
51+
<h3>{{ _("The Recombinant resource is out of date") }}{% snippet 'snippets/sysadmin_only.html' %}</h3>
5152
<p style="margin-bottom: 10px;">{{ _('You can refresh your resource in the database to try to solve the problem.') }}</p>
5253
<form id="create-pd-resource" method="post">
5354
{{ h.csrf_input() }}
54-
<button type="submit" class="btn btn-info mrgn-bttm-md m-b-3" name="refresh">{{_('Refresh…')}}</button>
55+
<button type="submit" class="btn btn-danger mrgn-bttm-md m-b-3" name="refresh-hard">{{_('Refresh…')}}</button>
5556
</form>
5657
</div>
5758
{% endif %}

ckanext/recombinant/views.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525

2626
from ckan.logic import ValidationError, NotAuthorized
2727
from ckan.model.group import Group
28-
from ckan.authz import has_user_permission_for_group_or_org
28+
from ckan.authz import has_user_permission_for_group_or_org, is_sysadmin
2929

3030
from ckan.views.dataset import _get_package_type
3131

@@ -533,10 +533,17 @@ def preview_table(resource_name: str,
533533
if 'create' in request.form:
534534
lc.action.recombinant_create(
535535
dataset_type=chromo['dataset_type'], owner_org=owner_org)
536-
else:
536+
elif 'refresh-hard' in request.form or 'refresh' in request.form:
537+
if not is_sysadmin(g.user):
538+
# only sysadmins can refresh via UI
539+
return abort(404)
540+
delete_fields = False
541+
if 'refresh-hard' in request.form:
542+
delete_fields = True
537543
lc.action.recombinant_update(
538544
dataset_type=chromo['dataset_type'], owner_org=owner_org,
539-
force_update=True)
545+
force_update=True,
546+
delete_fields=delete_fields)
540547
h.flash_success(_('Resources successfully refreshed.'))
541548
except NotAuthorized as e:
542549
return abort(403, e.message or '')

0 commit comments

Comments
 (0)