diff --git a/CHANGELOG.md b/CHANGELOG.md index 0cf4f0f217..26fd3a417a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,37 @@ This project does not yet adheres to [Semantic Versioning](https://semv \- +## [0.31.2] - 2023-03-09 + +# Added + +- Link from AssertedDistribution filter to BiologicalAssociations filter +- All tab to biological relationships facet [#3334] +- Biological Property to Manage controlled vocabulary terms + +### Changed + +- Add nomenclature code to relationships and statuses labels in Filter nomenclature [#3333] +- All Loan edit requests resolve to the edit task [#3330] + +### Fixed + +- Biological association filter raises [#3335] +- Mass annotator for Sources showed no options +- People filtering doesn't work on Filter nomenclature [#3332] +- Biological associations section shows incorrect results in Browse Otu [#3336] +- Error message on Combination [#3340] +- `Clone last citation` button doesn't work +- Missing asserted distributions in Browse OTU and Quick forms radial [#3337] + +[#3330]: https://github.com/SpeciesFileGroup/taxonworks/issues/3330 +[#3332]: https://github.com/SpeciesFileGroup/taxonworks/issues/3332 +[#3333]: https://github.com/SpeciesFileGroup/taxonworks/issues/3333 +[#3334]: https://github.com/SpeciesFileGroup/taxonworks/issues/3334 +[#3335]: https://github.com/SpeciesFileGroup/taxonworks/issues/3335 +[#3336]: https://github.com/SpeciesFileGroup/taxonworks/issues/3336 +[#3337]: https://github.com/SpeciesFileGroup/taxonworks/issues/3337 + ## [0.31.1] - 2023-03-07 ### Fixed @@ -24,6 +55,7 @@ This project does not yet adheres to [Semantic Versioning](https://semv - Short URLs not working due to Ruby 3.2 incompatibility. ### Changed + - `/combinations/` redirects to `/taxon_names/` [#3328]: https://github.com/SpeciesFileGroup/taxonworks/issues/3328 @@ -32,6 +64,7 @@ This project does not yet adheres to [Semantic Versioning](https://semv [#3327]: https://github.com/SpeciesFileGroup/taxonworks/issues/3327 [#3326]: https://github.com/SpeciesFileGroup/taxonworks/issues/3326 [#3325]: https://github.com/SpeciesFileGroup/taxonworks/issues/3325 +[#3324]: https://github.com/SpeciesFileGroup/taxonworks/issues/3324 ## [0.31.0] - 2023-03-07 @@ -3393,7 +3426,9 @@ This project does not yet adheres to [Semantic Versioning](https://semv - Loosing input page numbers when switching tabs on New Taxon Name task [#1532]: https://github.com/SpeciesFileGroup/taxonworks/issues/1532 -[unreleased]: https://github.com/SpeciesFileGroup/taxonworks/compare/v0.31.1...development + +[unreleased]: https://github.com/SpeciesFileGroup/taxonworks/compare/v0.31.2...development +[0.31.2]: https://github.com/SpeciesFileGroup/taxonworks/compare/v0.31.1...v0.31.2 [0.31.1]: https://github.com/SpeciesFileGroup/taxonworks/compare/v0.31.0...v0.31.1 [0.31.0]: https://github.com/SpeciesFileGroup/taxonworks/compare/v0.30.3...v0.31.0 [0.30.3]: https://github.com/SpeciesFileGroup/taxonworks/compare/v0.30.2...v0.30.3 diff --git a/app/assets/javascripts/views/loan_items/_form.js.erb b/app/assets/javascripts/views/loan_items/_form.js.erb deleted file mode 100644 index 92343bb1df..0000000000 --- a/app/assets/javascripts/views/loan_items/_form.js.erb +++ /dev/null @@ -1,113 +0,0 @@ -/* - - Code behind adding/remove loan items on /loan_items/:id/_form - - */ -var TW = TW || {}; -TW.views = TW.views || {}; -TW.views.loan_items = TW.views.loan_items || {}; -TW.views.loan_items.form = TW.views.loan_items.form || {}; - -Object.assign(TW.views.loan_items.form, { - - add_loan_item: function(form, gid, label) { - var random_index = new Date().getTime(); - var indexed_base_name = this.base_name + '[' + random_index + ']'; - var loan_item_list = form.find('.loan_items_list'); - - var type_regex = /gid:\/\/taxon-works\/(.*)\/\d+/; - var match = type_regex.exec(gid); - var item_type = match[1]; - - var total_field; - if (gid.match(/Otu/)) { - total_field = ''; - } else { - total_field = ''; - } - - form.append( $('')); - - loan_item_list.append( $('') - .append('' + label + '') - .append('') - .append('') - .append(total_field) - .append('' + item_type + '') - .append( this.remove_link() ) - ); - }, - - remove_link: function() { - var link = $('remove'); - this.bind_remove_links(link); - return link; - }, - - bind_remove_links: function(links) { - links.click(function () { - var list_item = $(this).closest('tr'); - var form = list_item.closest('form'); - var loan_item_id = list_item.data('loan-item-gid'); - var loan_item_index = list_item.data('loan-item-index'); - - if (loan_item_id != undefined) { - var loan_item_list = list_item.closest('.loan_items_list'); - - // if there is an ID from an existing item add the necessary (hidden) _destroy input - form.append($('') ); - form.append($('') ); - - TW.views.loans.form.warn_for_save(form.find('#loan_item_selector_message')); - } - list_item.remove(); - }); - }, - - warn_for_save: function(msg_div) { - msg_div.addClass('warning'); - msg_div.html('Update Loan click required to confirm removal/reorder of loan item.'); - }, - - bind_autocomplete_select_event: function(form) { - var input = $("#loan_item_autocomplete"); - input.on( "autocompleteselect", function( event, ui ) { - - TW.views.loans.form.add_loan_item( $('#loan_item_selector'), ui.item.gid, ui.item.label); - - form.find("#loan_item_object_gid").append($('') ); - form.find("#loan_item_label").html(ui.item.label); - - input.val(""); - return false; - } ); - }, - - set_loan_item: function(form) { - - }, - - initialize: function(form) { - // Bind injected datepicker elements - $('body').on('focus',".datepicker_recurring_start", function() { - $(this).datepicker(); - }); - - TW.views.loan_items.select_loan_item.initialize_select_loan_items(); - this.bind_autocomplete_select_event(form); - - // this.bind_remove_links(form.find('.remove_loan_item')); - // this.make_list_sortable(form); - // this.bind_position_handling_to_submit_button(form); - } -} -); - -$(document).on('turbolinks:load', function() { - if ( $('.loan_item_form').length ) { - TW.views.loan_items.form.initialize($('.loan_item_form')); - } - } -) - - diff --git a/app/assets/javascripts/views/loans/_form.js.erb b/app/assets/javascripts/views/loans/_form.js.erb deleted file mode 100644 index ed75c85a01..0000000000 --- a/app/assets/javascripts/views/loans/_form.js.erb +++ /dev/null @@ -1,132 +0,0 @@ -/* - - Code behind adding/remove loan items on /loan/:id/edit - - */ -var TW = TW || {}; -TW.views = TW.views || {}; -TW.views.loans = TW.views.loans || {}; -TW.views.loans.form = TW.views.loans.form || {}; - -Object.assign(TW.views.loans.form, { - - base_name: 'loan[loan_items_attributes]', - - add_loan_item: function(form, gid, label) { - var random_index = new Date().getTime(); - var indexed_base_name = this.base_name + '[' + random_index + ']'; - var loan_item_list = form.find('.loan_items_list'); - - var type_regex = /gid:\/\/taxon-works\/(.*)\/\d+/; - var match = type_regex.exec(gid); - var item_type = match[1]; - - var total_field; - if (gid.match(/Otu/)) { - total_field = ''; - } else { - total_field = ''; - } - - form.append( $('')); - - loan_item_list.append( $('') - .append('' + label + '') - .append('') - .append('') - .append(total_field) - .append('' + item_type + '') - .append( this.remove_link() ) - ); - }, - - remove_link: function() { - var link = $('remove'); - this.bind_remove_links(link); - return link; - }, - - bind_remove_links: function(links) { - links.click(function () { - var list_item = $(this).closest('tr'); - var form = list_item.closest('form'); - var loan_item_id = list_item.data('loan-item-gid'); - var loan_item_index = list_item.data('loan-item-index'); - - if (loan_item_id != undefined) { - var loan_item_list = list_item.closest('.loan_items_list'); - - // if there is an ID from an existing item add the necessary (hidden) _destroy input - form.append($('') ); - form.append($('') ); - - TW.views.loans.form.warn_for_save(form.find('#loan_item_selector_message')); - } - list_item.remove(); - }); - }, - - warn_for_save: function(msg_div) { - msg_div.addClass('warning'); - msg_div.html('Update Loan click required to confirm removal/reorder of loan item.'); - }, - - make_list_sortable: function(form) { - var list_items = form.find('.loan_items_list'); - list_items.sortable({ - change: function() { - if ($('form[id^="new_"]').length == 0) { - TW.views.loans.form.warn_for_save(form.find('#loan_item_selector_message')); - } - } - }); - }, - - bind_position_handling_to_submit_button: function(form) { - form.closest('form').find('input[name="commit"]').click(function () { - var i = 1; - var loan_item_index; - form.find('.loan_item').each( function() { - console.log($(this)); - loan_item_index = $(this).data('loan-item-index'); - $(this).append( - $('') - ); - i = i + 1; - }); - }); - }, - - bind_autocomplete_select_event: function() { - var input = $("#loan_item_autocomplete"); - input.on( "autocompleteselect", function( event, ui ) { - TW.views.loans.form.add_loan_item( $('#loan_item_selector'), ui.item.gid, ui.item.label); - input.val(""); - return false; - } ); - }, - - initialize_selector: function(form) { - // Bind injected datepicker elements - $('body').on('focus',".datepicker_recurring_start", function() { - $(this).datepicker(); - }); - - TW.views.loan_items.select_loan_item.initialize_select_loan_items(); - this.bind_autocomplete_select_event(); - - this.bind_remove_links(form.find('.remove_loan_item')); - this.make_list_sortable(form); - this.bind_position_handling_to_submit_button(form); - } -} -); - - -$(document).on("turbolinks:load", function() { - if ( $('#loan_item_selector').length ) { - TW.views.loans.form.initialize_selector($('#loan_item_selector')); - } -}) - - diff --git a/app/assets/javascripts/views/loans/_select_loan_item.js.erb b/app/assets/javascripts/views/loans/_select_loan_item.js.erb deleted file mode 100644 index 43751da9ef..0000000000 --- a/app/assets/javascripts/views/loans/_select_loan_item.js.erb +++ /dev/null @@ -1,64 +0,0 @@ -/* - - !! Initialized in parent. - Code behind selecting a loan item. - -*/ - -var TW = TW || {}; -TW.views = TW.views || {}; -TW.views.loan_items = TW.views.loan_items || {}; -TW.views.loan_items.select_loan_item = TW.views.select_loan_item || {}; - -Object.assign(TW.views.loan_items.select_loan_item, { - - base_name: 'loan[loan_items_attributes]', - - get_autocomplete_path: function(element) { - return('/' + element.find('input[type=radio][name=autocomplete_type]:checked').val() + '/autocomplete'); - }, - - initialize_autocomplete: function(element, select_function) { - var autocomplete_input = element.find("#loan_item_autocomplete"); - var autocomplete_source = this.get_autocomplete_path(element); - - autocomplete_input.autocomplete({ - source: autocomplete_source, - - // bind select: action in page specific usages - - response: function(event, ui) { - // ui.content is the array that's about to be sent to the response callback. - if (ui.content.length === 0) { - $("#loan_item_not_found").text("No results found."); - } else { - $("#loan_item_not_found").empty(); - } - } - - }).autocomplete("instance")._renderItem = function (ul, item) { - return $("
  • ") - .append("" + item.label + "") - .appendTo(ul); - }; - }, - - bind_autocomplete_source_to_radio_buttons: function(element) { - $('input[type=radio][name=autocomplete_type]').on('change', function() { - element.find("#loan_item_autocomplete").autocomplete({ - source: TW.views.loan_items.select_loan_item.get_autocomplete_path(element) - }); - $("#loan_item_not_found").empty(); - $("#loan_item_autocomplete").val(''); - } - ); - }, - - initialize_select_loan_items: function() { - var div = $( "#select_loan_item" ); - this.initialize_autocomplete(div); - this.bind_autocomplete_source_to_radio_buttons(div); - } -}); - - diff --git a/app/controllers/loans_controller.rb b/app/controllers/loans_controller.rb index 83766d18a9..c86f2b3200 100644 --- a/app/controllers/loans_controller.rb +++ b/app/controllers/loans_controller.rb @@ -41,6 +41,7 @@ def new # GET /loans/1/edit def edit + redirect_to edit_loan_task_path(id: params[:id]) end # POST /loans @@ -97,7 +98,7 @@ def destroy def list @loans = Loan.includes(:identifiers).with_project_id(sessions_current_project_id) - .order(Arel.sql("LENGTH(identifier), identifier")).references(:identifiers).page(params[:page]) #.per(10) #.per(3) + .order(Arel.sql('LENGTH(identifier), identifier')).references(:identifiers).page(params[:page]) end def search diff --git a/app/helpers/annotations_helper.rb b/app/helpers/annotations_helper.rb index feebf722a0..ad5933ce72 100644 --- a/app/helpers/annotations_helper.rb +++ b/app/helpers/annotations_helper.rb @@ -6,12 +6,19 @@ module AnnotationsHelper # see /metadata/annotators.json def klass_annotations j = {} - ::Project::MANIFEST.sort.each do |m| - k = m.safe_constantize - if k.respond_to?(:available_annotation_types) + ::Project::MANIFEST.sort.each do |m| + k = m.safe_constantize + if k.respond_to?(:available_annotation_types) j[k.name] = k.available_annotation_types - end - end + end + end + + # Community classes that can be referenced in Filters + # at minimum need to be here + j.merge!( + 'Source' => Source.available_annotation_types + ) + j end @@ -19,13 +26,13 @@ def klass_annotations # Assumes the context is the object, not a multi-object summary def annotations_summary_tag(object) v = [citation_list_tag(object), - identifier_list_tag(object), - data_attribute_list_tag(object), - note_list_tag(object), - tag_list_tag(object), - alternate_values_list_tag(object), - confidence_list_tag(object), - attribution_list_tag(object) + identifier_list_tag(object), + data_attribute_list_tag(object), + note_list_tag(object), + tag_list_tag(object), + alternate_values_list_tag(object), + confidence_list_tag(object), + attribution_list_tag(object) ].compact tag.div(class: %w{item panel separate-bottom}) do diff --git a/app/javascript/vue/components/Filter/Facets/BiologicalAssociation/FacetBiologicalProperty.vue b/app/javascript/vue/components/Filter/Facets/BiologicalAssociation/FacetBiologicalProperty.vue index 8414a96b30..0201955970 100644 --- a/app/javascript/vue/components/Filter/Facets/BiologicalAssociation/FacetBiologicalProperty.vue +++ b/app/javascript/vue/components/Filter/Facets/BiologicalAssociation/FacetBiologicalProperty.vue @@ -2,10 +2,13 @@

    Biological property

    - @@ -45,9 +48,9 @@ diff --git a/app/javascript/vue/components/Filter/Facets/BiologicalAssociation/FacetBiologicalRelationship.vue b/app/javascript/vue/components/Filter/Facets/BiologicalAssociation/FacetBiologicalRelationship.vue index ae52e1295c..bda32adcad 100644 --- a/app/javascript/vue/components/Filter/Facets/BiologicalAssociation/FacetBiologicalRelationship.vue +++ b/app/javascript/vue/components/Filter/Facets/BiologicalAssociation/FacetBiologicalRelationship.vue @@ -5,6 +5,9 @@ @@ -91,6 +91,7 @@ import SmartSelector from 'components/ui/SmartSelector.vue' import SmartSelectorItem from 'components/ui/SmartSelectorItem.vue' import VBtn from 'components/ui/VBtn/index.vue' import VLock from 'components/ui/VLock' +import { getCurrentUserId } from 'helpers/user' const STORAGE = { lock: 'radialObject::source::lock', @@ -152,12 +153,12 @@ const emit = defineEmits([ const citation = computed({ get: () => props.modelValue, - set: value => emit('update:modelValue', value) + set: (value) => emit('update:modelValue', value) }) const isAbsent = computed({ get: () => props.absent, - set: value => emit('update:absent', value) + set: (value) => emit('update:absent', value) }) const isLocked = ref(false) @@ -165,35 +166,26 @@ const isLocked = ref(false) const sourceId = computed(() => props.modelValue.source_id) const source = ref(undefined) -watch( - sourceId, - async (newId, oldId) => { - if (newId) { - if (newId !== oldId && newId !== source.value?.id) { - source.value = (await Source.find(newId)).body - } - } else { - source.value = undefined +watch(sourceId, async (newId, oldId) => { + if (newId) { + if (newId !== oldId && newId !== source.value?.id) { + source.value = (await Source.find(newId)).body } + } else { + source.value = undefined } -) +}) -watch( - isAbsent, - newVal => { - sessionStorage.setItem(STORAGE.isAbsent, newVal) - } -) +watch(isAbsent, (newVal) => { + sessionStorage.setItem(STORAGE.isAbsent, newVal) +}) -watch( - isLocked, - newVal => { - sessionStorage.setItem(STORAGE.lock, newVal) - emit('lock', newVal) - } -) +watch(isLocked, (newVal) => { + sessionStorage.setItem(STORAGE.lock, newVal) + emit('lock', newVal) +}) -function setSource (value) { +function setSource(value) { source.value = value sessionStorage.setItem(STORAGE.sourceId, value.id) citation.value.source_id = value.id @@ -201,32 +193,31 @@ function setSource (value) { emit('source', value) } -function setPage (e) { +function setPage(e) { sessionStorage.setItem(STORAGE.pages, e.target.value) } -function setIsOriginal (e) { +function setIsOriginal(e) { sessionStorage.setItem(STORAGE.isOriginal, e.target.value) } -function setLastCitation () { - Citation.where({ recent: true, per: 1, user_id: true }).then(({ body }) => { - const [mostRecentCitation] = body +function setLastCitation() { + Citation.where({ recent: true, per: 1, user_id: getCurrentUserId() }).then( + ({ body }) => { + const [mostRecentCitation] = body - if (mostRecentCitation) { - Object.assign( - citation.value, - { + if (mostRecentCitation) { + Object.assign(citation.value, { pages: mostRecentCitation.pages, source_id: mostRecentCitation.source_id, is_original: mostRecentCitation.is_original - } - ) + }) + } } - }) + ) } -function init () { +function init() { const lockStoreValue = convertType(sessionStorage.getItem(STORAGE.lock)) if (lockStoreValue) { @@ -234,13 +225,16 @@ function init () { } if (props.lockButton && lockStoreValue) { - citation.value.source_id = convertType(sessionStorage.getItem(STORAGE.sourceId)) - citation.value.is_original = convertType(sessionStorage.getItem(STORAGE.isOriginal)) + citation.value.source_id = convertType( + sessionStorage.getItem(STORAGE.sourceId) + ) + citation.value.is_original = convertType( + sessionStorage.getItem(STORAGE.isOriginal) + ) citation.value.pages = convertType(sessionStorage.getItem(STORAGE.pages)) isAbsent.value = convertType(sessionStorage.getItem(STORAGE.isAbsent)) } } onMounted(() => init()) - diff --git a/app/javascript/vue/components/layout/Filter/FilterList.vue b/app/javascript/vue/components/layout/Filter/FilterList.vue index bec59ab4bf..47db0b90e1 100644 --- a/app/javascript/vue/components/layout/Filter/FilterList.vue +++ b/app/javascript/vue/components/layout/Filter/FilterList.vue @@ -63,7 +63,6 @@ v-for="(_, attr) in attributes" :key="attr" v-html="item[attr]" - @click="sortTable(attr)" /> diff --git a/app/javascript/vue/components/radials/filter/links/AssertedDistribution.js b/app/javascript/vue/components/radials/filter/links/AssertedDistribution.js index 497c6eae44..ca8df11ca5 100644 --- a/app/javascript/vue/components/radials/filter/links/AssertedDistribution.js +++ b/app/javascript/vue/components/radials/filter/links/AssertedDistribution.js @@ -1,11 +1,13 @@ import { FILTER_OTU, FILTER_SOURCE, - FILTER_TAXON_NAME + FILTER_TAXON_NAME, + FILTER_BIOLOGICAL_ASSOCIATION } from '../constants/filterLinks' export const AssertedDistribution = [ FILTER_SOURCE, FILTER_OTU, - FILTER_TAXON_NAME + FILTER_TAXON_NAME, + FILTER_BIOLOGICAL_ASSOCIATION ] diff --git a/app/javascript/vue/components/radials/object/components/asserted_distributions/asserted_distributions_annotator.vue b/app/javascript/vue/components/radials/object/components/asserted_distributions/asserted_distributions_annotator.vue index 29ef9e56b3..542d5a4e17 100644 --- a/app/javascript/vue/components/radials/object/components/asserted_distributions/asserted_distributions_annotator.vue +++ b/app/javascript/vue/components/radials/object/components/asserted_distributions/asserted_distributions_annotator.vue @@ -49,11 +49,20 @@
    + \ No newline at end of file +} + diff --git a/app/javascript/vue/routes/endpoints/base.js b/app/javascript/vue/routes/endpoints/base.js index 1ad879c371..b96ef0a774 100644 --- a/app/javascript/vue/routes/endpoints/base.js +++ b/app/javascript/vue/routes/endpoints/base.js @@ -1,4 +1,5 @@ import AjaxCall from 'helpers/ajaxCall' +import getPagination from 'helpers/getPagination' import { isObject } from 'helpers/objects' const BASE_PARAMS = { @@ -15,12 +16,14 @@ const filterParams = (params, allowParams) => { return params } - properties.forEach(property => { + properties.forEach((property) => { if (allowProperties.includes(property)) { const paramValue = params[property] if (Array.isArray(paramValue)) { - newObj[property] = paramValue.map(item => filterParams(item, allowParams[property])) + newObj[property] = paramValue.map((item) => + filterParams(item, allowParams[property]) + ) } else if (isObject(paramValue)) { newObj[property] = filterParams(paramValue, allowParams[property]) } else { @@ -33,41 +36,87 @@ const filterParams = (params, allowParams) => { } export default (model, permitParams) => ({ - all: params => AjaxCall('get', `/${model}.json`, { params }), - - create: (data, config) => AjaxCall('post', `/${model}.json`, filterParams(data, { ...BASE_PARAMS, ...permitParams }), config), - - destroy: id => AjaxCall('delete', `/${model}/${id}.json`), - - find: (id, params, config) => AjaxCall('get', `/${model}/${id}.json`, { params }, config), - - update: (id, data, config) => AjaxCall('patch', `/${model}/${id}.json`, filterParams(data, { ...BASE_PARAMS, ...permitParams }), config), + all: async (params = {}) => { + const url = `/${model}.json` + const maxPer = params.per || 500 + const requests = [ + await AjaxCall('get', url, { + params: { + ...params, + per: maxPer + } + }) + ] + const { totalPages } = getPagination(requests[0]) + + if (totalPages > 1) { + for (let page = 2; page <= totalPages; page++) { + requests.push(AjaxCall('get', url, { params: { ...params, page } })) + } + } - where: (params, config) => AjaxCall('get', `/${model}.json`, { params }, config), + const responses = await Promise.all(requests) - autocomplete: (params, config) => AjaxCall('get', `/${model}/autocomplete`, { params }, config) + return { + body: [].concat(...responses.map(({ body }) => body)) + } + }, + + create: (data, config) => + AjaxCall( + 'post', + `/${model}.json`, + filterParams(data, { ...BASE_PARAMS, ...permitParams }), + config + ), + + destroy: (id) => AjaxCall('delete', `/${model}/${id}.json`), + + find: (id, params, config) => + AjaxCall('get', `/${model}/${id}.json`, { params }, config), + + update: (id, data, config) => + AjaxCall( + 'patch', + `/${model}/${id}.json`, + filterParams(data, { ...BASE_PARAMS, ...permitParams }), + config + ), + + where: (params, config) => + AjaxCall('get', `/${model}.json`, { params }, config), + + autocomplete: (params, config) => + AjaxCall('get', `/${model}/autocomplete`, { params }, config) }) -export { - filterParams -} +export { filterParams } -export const annotations = model => ({ - attributions: (id, params) => AjaxCall('get', `/${model}/${id}/attributions.json`, { params }), +export const annotations = (model) => ({ + attributions: (id, params) => + AjaxCall('get', `/${model}/${id}/attributions.json`, { params }), - citations: (id, params) => AjaxCall('get', `/${model}/${id}/citations.json`, { params }), + citations: (id, params) => + AjaxCall('get', `/${model}/${id}/citations.json`, { params }), - dataAttributes: (id, params) => AjaxCall('get', `/${model}/${id}/data_attributes.json`, { params }), + dataAttributes: (id, params) => + AjaxCall('get', `/${model}/${id}/data_attributes.json`, { params }), - depictions: (id, params) => AjaxCall('get', `/${model}/${id}/depictions.json`, { params }), + depictions: (id, params) => + AjaxCall('get', `/${model}/${id}/depictions.json`, { params }), - documentation: (id, params) => AjaxCall('get', `/${model}/${id}/documentation.json`, { params }), + documentation: (id, params) => + AjaxCall('get', `/${model}/${id}/documentation.json`, { params }), - identifiers: (id, params) => AjaxCall('get', `/${model}/${id}/identifiers.json`, { params }), + identifiers: (id, params) => + AjaxCall('get', `/${model}/${id}/identifiers.json`, { params }), - notes: (id, params) => AjaxCall('get', `/${model}/${id}/notes.json`, { params }), + notes: (id, params) => + AjaxCall('get', `/${model}/${id}/notes.json`, { params }), - tags: (id, params) => AjaxCall('get', `/${model}/${id}/tags.json`, { params }), + tags: (id, params) => + AjaxCall('get', `/${model}/${id}/tags.json`, { params }), - protocolRelationships: (id, params) => AjaxCall('get', `/${model}/${id}/protocol_relationships.json`, { params }) + protocolRelationships: (id, params) => + AjaxCall('get', `/${model}/${id}/protocol_relationships.json`, { params }) }) diff --git a/app/javascript/vue/tasks/controlled_vocabularies/manage/constants/controlled_vocabulary_term_types.js b/app/javascript/vue/tasks/controlled_vocabularies/manage/constants/controlled_vocabulary_term_types.js index cb5fc0925a..3962ca7590 100644 --- a/app/javascript/vue/tasks/controlled_vocabularies/manage/constants/controlled_vocabulary_term_types.js +++ b/app/javascript/vue/tasks/controlled_vocabularies/manage/constants/controlled_vocabulary_term_types.js @@ -4,5 +4,6 @@ export default { Predicate: 'A predicate is the label for a custom field/attribute.', ConfidenceLevel: 'A confidence level is a curator defined status that pertains to their confidence in some quality of the data it is applied to.', BiocurationGroup: 'A biocuration group groups biocurations classes into categories, like "Life Stage" or "Sex."', - BiocurationClass: 'A biocuration class is a biological property that curators use to describe their specimens, like Female, or adult.' + BiocurationClass: 'A biocuration class is a biological property that curators use to describe their specimens, like Female, or adult.', + BiologicalProperty: 'A biological class that is assigned to the subject or object of a BiologicalAssociation through their use in the definition of a BiologicalRelationship. For example host or parasitod.' } diff --git a/app/javascript/vue/tasks/nomenclature/filter/components/recursiveList.vue b/app/javascript/vue/tasks/nomenclature/filter/components/recursiveList.vue index 81f0601731..567c3d09b9 100644 --- a/app/javascript/vue/tasks/nomenclature/filter/components/recursiveList.vue +++ b/app/javascript/vue/tasks/nomenclature/filter/components/recursiveList.vue @@ -2,20 +2,23 @@
    • + :key="key" + > + :object-list="item" + />
    @@ -56,15 +59,15 @@ export default { sortable.sort((a, b) => { if (a[1][this.display] > b[1][this.display]) { - return 1; + return 1 } if (a[1][this.display] < b[1][this.display]) { - return -1; + return -1 } - return 0; + return 0 }) - sortable.forEach(item => { + sortable.forEach((item) => { sortableObject[item[0]] = item[1] }) @@ -73,29 +76,28 @@ export default { }, methods: { - selectItem (optionSelected) { + selectItem(optionSelected) { this.$emit('selected', optionSelected) }, - findExist (item) { - return this.created.find(element => element.type == item.type) + findExist(item) { + return this.created.find((element) => element.type == item.type) }, - isForThisRank (item) { + isForThisRank(item) { return item.valid_subject_ranks?.includes(this.taxon.rank_string) } } } - diff --git a/app/javascript/vue/tasks/otu/browse/store/actions/loadAssertedDistributions.js b/app/javascript/vue/tasks/otu/browse/store/actions/loadAssertedDistributions.js index 59faa802bd..9046a4bd55 100644 --- a/app/javascript/vue/tasks/otu/browse/store/actions/loadAssertedDistributions.js +++ b/app/javascript/vue/tasks/otu/browse/store/actions/loadAssertedDistributions.js @@ -2,10 +2,7 @@ import { AssertedDistribution } from 'routes/endpoints' import { MutationNames } from '../mutations/mutations' import nonReactiveStore from '../nonReactiveStore.js' -const embed = [ - 'shape', - 'lavel_names' -] +const embed = ['shape', 'lavel_names'] const extend = [ 'citations', 'geographic_area', @@ -16,31 +13,41 @@ const extend = [ 'otu' ] -export default ({ commit }, otusId) => new Promise((resolve, reject) => { - AssertedDistribution.where({ otu_id: otusId, embed, extend }).then(response => { - const shapes = response.body.map(item => item.geographic_area.shape) +export default ({ commit }, otusId) => + new Promise((resolve, reject) => { + AssertedDistribution.all({ otu_id: otusId, embed, extend }).then( + (response) => { + const shapes = response.body.map((item) => item.geographic_area.shape) - nonReactiveStore.geographicAreas = [...new Map(shapes.map(item => [item.properties.geographic_area.id, item])).values()] + nonReactiveStore.geographicAreas = [ + ...new Map( + shapes.map((item) => [item.properties.geographic_area.id, item]) + ).values() + ] - const assertedDistributions = response.body.map(ad => { - ad.geographic_area.shape = !!ad.geographic_area.shape + const assertedDistributions = response.body + .map((ad) => { + ad.geographic_area.shape = !!ad.geographic_area.shape - return ad - }).sort((a, b) => { - const compareA = a.geographic_area.name - const compareB = b.geographic_area.name - if (compareA < compareB) { - return -1 - } else if (compareA > compareB) { - return 1 - } else { - return 0 - } - }) + return ad + }) + .sort((a, b) => { + const compareA = a.geographic_area.name + const compareB = b.geographic_area.name + if (compareA < compareB) { + return -1 + } else if (compareA > compareB) { + return 1 + } else { + return 0 + } + }) - commit(MutationNames.SetAssertedDistributions, assertedDistributions) - resolve(response) - }, error => { - reject(error) + commit(MutationNames.SetAssertedDistributions, assertedDistributions) + resolve(response) + }, + (error) => { + reject(error) + } + ) }) -}) diff --git a/app/javascript/vue/tasks/otu/browse/store/actions/loadBiologicalAssociations.js b/app/javascript/vue/tasks/otu/browse/store/actions/loadBiologicalAssociations.js index 74e1c6d838..3870ab9c6e 100644 --- a/app/javascript/vue/tasks/otu/browse/store/actions/loadBiologicalAssociations.js +++ b/app/javascript/vue/tasks/otu/browse/store/actions/loadBiologicalAssociations.js @@ -12,10 +12,16 @@ const extend = [ export default ({ state, commit }, globalId) => new Promise((resolve, reject) => { - BiologicalAssociation.where({ any_global_id: globalId, extend }).then(response => { - commit(MutationNames.SetBiologicalAssociations, state.biologicalAssociations.concat(response.body)) - resolve(response) - }, error => { - reject(error) - }) + BiologicalAssociation.all({ any_global_id: [globalId], extend }).then( + (response) => { + commit( + MutationNames.SetBiologicalAssociations, + state.biologicalAssociations.concat(response.body) + ) + resolve(response) + }, + (error) => { + reject(error) + } + ) }) diff --git a/app/javascript/vue/tasks/otu/browse/store/actions/loadCollectingEvents.js b/app/javascript/vue/tasks/otu/browse/store/actions/loadCollectingEvents.js index 0daff79efe..9d45bcb57b 100644 --- a/app/javascript/vue/tasks/otu/browse/store/actions/loadCollectingEvents.js +++ b/app/javascript/vue/tasks/otu/browse/store/actions/loadCollectingEvents.js @@ -7,7 +7,7 @@ const maxCEPerCall = 100 export default ({ state, commit }, otusId) => new Promise((resolve, reject) => { - CollectingEvent.where({ otu_id: otusId }) + CollectingEvent.all({ otu_id: otusId }) .then( (response) => { const CEs = response.body @@ -23,9 +23,7 @@ export default ({ state, commit }, otusId) => ) if (CEs.length) { CEIds.forEach((idGroup) => { - promises.push( - Georeference.where({ collecting_event_id: idGroup }) - ) + promises.push(Georeference.all({ collecting_event_id: idGroup })) }) Promise.all(promises).then((responses) => { diff --git a/app/javascript/vue/tasks/otu/browse/store/actions/loadCollectionObjects.js b/app/javascript/vue/tasks/otu/browse/store/actions/loadCollectionObjects.js index b420e1d5c9..d041c927f1 100644 --- a/app/javascript/vue/tasks/otu/browse/store/actions/loadCollectionObjects.js +++ b/app/javascript/vue/tasks/otu/browse/store/actions/loadCollectionObjects.js @@ -3,7 +3,7 @@ import { MutationNames } from '../mutations/mutations' export default ({ state, commit }, otuId) => new Promise((resolve, reject) => { - CollectionObject.where({ + CollectionObject.all({ otu_id: otuId, current_determinations: true, extend: ['citations', 'source'] diff --git a/app/javascript/vue/tasks/otu/browse/store/actions/loadCommonNames.js b/app/javascript/vue/tasks/otu/browse/store/actions/loadCommonNames.js index accd4d578c..93561c82fe 100644 --- a/app/javascript/vue/tasks/otu/browse/store/actions/loadCommonNames.js +++ b/app/javascript/vue/tasks/otu/browse/store/actions/loadCommonNames.js @@ -2,6 +2,9 @@ import { MutationNames } from '../mutations/mutations' import { CommonName } from 'routes/endpoints' export default ({ commit, state }, id) => - CommonName.where({ otu_id: id }).then(response => { - commit(MutationNames.SetCommonNames, state.commonNames.concat(response.body)) + CommonName.all({ otu_id: id }).then((response) => { + commit( + MutationNames.SetCommonNames, + state.commonNames.concat(response.body) + ) }) diff --git a/app/javascript/vue/tasks/otu/browse/store/actions/loadDescendants.js b/app/javascript/vue/tasks/otu/browse/store/actions/loadDescendants.js index 58f78881c5..a8b507ce47 100644 --- a/app/javascript/vue/tasks/otu/browse/store/actions/loadDescendants.js +++ b/app/javascript/vue/tasks/otu/browse/store/actions/loadDescendants.js @@ -23,7 +23,7 @@ function getAllCollectingEvents(taxonNames) { chunks.forEach((ids) => { if (ids.length) { promises.push( - CollectingEvent.where({ otu_id: [].concat(...ids) }).then( + CollectingEvent.all({ otu_id: [].concat(...ids) }).then( (response) => { collectingEvents.push(response.body) } @@ -55,7 +55,7 @@ function getAllGeoreferences(CEIds) { if (chunks.length) { chunks.forEach((ids) => { promises.push( - Georeference.where({ collecting_event_id: ids }).then((response) => { + Georeference.all({ collecting_event_id: ids }).then((response) => { georeferences.push(response.body) }) ) @@ -81,7 +81,7 @@ export default ({ commit, state }, otu) => { georeferences: [] } - TaxonName.where(params) + TaxonName.all(params) .then((response) => { descendants.taxon_names = response.body.filter( (tn) => tn.id !== otu.taxon_name_id diff --git a/app/javascript/vue/tasks/otu/browse/store/actions/loadInformation.js b/app/javascript/vue/tasks/otu/browse/store/actions/loadInformation.js index ce6f1a3244..8c7846340d 100644 --- a/app/javascript/vue/tasks/otu/browse/store/actions/loadInformation.js +++ b/app/javascript/vue/tasks/otu/browse/store/actions/loadInformation.js @@ -3,13 +3,14 @@ import { MutationNames } from '../mutations/mutations' import { TaxonName } from 'routes/endpoints' export default ({ dispatch, commit, state }, otus) => { - const otuIds = otus.map(otu => otu.id) + const otuIds = otus.map((otu) => otu.id) - function loadOtuInformation (otu) { + function loadOtuInformation(otu) { const promises = [] return new Promise((resolve, reject) => { - - promises.push(dispatch(ActionNames.LoadBiologicalAssociations, otu.global_id)) + promises.push( + dispatch(ActionNames.LoadBiologicalAssociations, otu.global_id) + ) promises.push(dispatch(ActionNames.LoadDepictions, otu.id)) promises.push(dispatch(ActionNames.LoadCommonNames, otu.id)) @@ -21,7 +22,9 @@ export default ({ dispatch, commit, state }, otus) => { if (state.currentOtu.taxon_name_id) { dispatch(ActionNames.LoadTaxonName, state.currentOtu.taxon_name_id) } - TaxonName.where({ taxon_name_id: [...new Set(otus.map(otu => otu.taxon_name_id))] }).then(response => { + TaxonName.all({ + taxon_name_id: [...new Set(otus.map((otu) => otu.taxon_name_id))] + }).then((response) => { commit(MutationNames.SetTaxonNames, response.body) }) @@ -42,5 +45,8 @@ export default ({ dispatch, commit, state }, otus) => { state.loadState.assertedDistribution = false } processArray(otus) - dispatch(ActionNames.LoadAssertedDistributions, state.otus.map(otu => otu.id)) + dispatch( + ActionNames.LoadAssertedDistributions, + state.otus.map((otu) => otu.id) + ) } diff --git a/app/javascript/vue/tasks/otu/filter/components/FilterView.vue b/app/javascript/vue/tasks/otu/filter/components/FilterView.vue index d2eb030c1c..3def2b8069 100644 --- a/app/javascript/vue/tasks/otu/filter/components/FilterView.vue +++ b/app/javascript/vue/tasks/otu/filter/components/FilterView.vue @@ -3,27 +3,28 @@ v-model="params" input-id="area_picker_autocomplete" /> - + + - - + - + + date2 && subject_invalid_statuses.empty? - soft_validations.add(:type, "#{self.subject_status.capitalize} #{self.subject_taxon_name.cached_html_name_and_author_year} should not be younger than citation (#{self.object_taxon_name.source.author_year}) of #{self.object_taxon_name.cached_html_name_and_author_year}") + soft_validations.add(:type, "#{self.subject_status.capitalize} #{self.subject_taxon_name.cached_html_name_and_author_year} should not be younger than citation (#{self.object_taxon_name.source&.author_year}) of #{self.object_taxon_name.cached_html_name_and_author_year}") end end diff --git a/config/initializers/vendor/kaminari_config.rb b/config/initializers/vendor/kaminari_config.rb index 632bf1d276..34f3499240 100644 --- a/config/initializers/vendor/kaminari_config.rb +++ b/config/initializers/vendor/kaminari_config.rb @@ -1,5 +1,5 @@ Kaminari.configure do |config| - config.default_per_page = 25 + config.default_per_page = 50 config.max_per_page = 10000 # config.window = 4 # config.outer_window = 0 diff --git a/db/schema.rb b/db/schema.rb index 8c5466fff7..57d0ea3c20 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2023_01_13_094500) do +ActiveRecord::Schema.define(version: 2023_01_13_090400) do # These are extensions that must be enabled in order to support this database enable_extension "fuzzystrmatch" @@ -379,8 +379,8 @@ end create_table "confidences", id: :serial, force: :cascade do |t| - t.integer "confidence_object_id", null: false t.string "confidence_object_type", null: false + t.integer "confidence_object_id", null: false t.integer "position", null: false t.integer "created_by_id", null: false t.integer "updated_by_id", null: false @@ -612,8 +612,8 @@ end create_table "documentation", id: :serial, force: :cascade do |t| - t.integer "documentation_object_id", null: false t.string "documentation_object_type", null: false + t.integer "documentation_object_id", null: false t.integer "document_id", null: false t.integer "project_id", null: false t.integer "created_by_id", null: false @@ -631,7 +631,7 @@ create_table "documents", id: :serial, force: :cascade do |t| t.string "document_file_file_name", null: false t.string "document_file_content_type", null: false - t.integer "document_file_file_size", null: false + t.bigint "document_file_file_size", null: false t.datetime "document_file_updated_at", null: false t.integer "project_id", null: false t.integer "created_by_id", null: false @@ -840,8 +840,8 @@ t.string "vernacularName" t.string "waterBody" t.string "year" - t.integer "dwc_occurrence_object_id" t.string "dwc_occurrence_object_type" + t.integer "dwc_occurrence_object_id" t.integer "created_by_id", null: false t.integer "updated_by_id", null: false t.integer "project_id" @@ -1040,7 +1040,7 @@ t.datetime "updated_at", null: false t.string "image_file_file_name" t.string "image_file_content_type" - t.integer "image_file_file_size" + t.bigint "image_file_file_size" t.datetime "image_file_updated_at" t.integer "updated_by_id", null: false t.text "image_file_meta" @@ -1121,8 +1121,8 @@ t.integer "project_id", null: false t.datetime "created_at", null: false t.datetime "updated_at", null: false - t.integer "loan_item_object_id" t.string "loan_item_object_type" + t.integer "loan_item_object_id" t.integer "total" t.string "disposition" t.index ["created_by_id"], name: "index_loan_items_on_created_by_id" @@ -1151,7 +1151,7 @@ t.datetime "updated_at", null: false t.string "recipient_honorific" t.string "recipient_country" - t.text "lender_address", default: "Lender's address not provided.", null: false + t.text "lender_address", null: false t.boolean "is_gift" t.index ["created_by_id"], name: "index_loans_on_created_by_id" t.index ["project_id"], name: "index_loans_on_project_id" @@ -1347,10 +1347,10 @@ end create_table "origin_relationships", id: :serial, force: :cascade do |t| - t.integer "old_object_id", null: false t.string "old_object_type", null: false - t.integer "new_object_id", null: false + t.integer "old_object_id", null: false t.string "new_object_type", null: false + t.integer "new_object_id", null: false t.integer "position" t.integer "created_by_id", null: false t.integer "updated_by_id", null: false @@ -1434,8 +1434,8 @@ end create_table "pinboard_items", id: :serial, force: :cascade do |t| - t.integer "pinned_object_id", null: false t.string "pinned_object_type", null: false + t.integer "pinned_object_id", null: false t.integer "user_id", null: false t.integer "project_id", null: false t.integer "position", null: false @@ -1499,7 +1499,7 @@ t.datetime "updated_at", null: false t.integer "created_by_id", null: false t.integer "updated_by_id", null: false - t.jsonb "preferences", default: {}, null: false + t.jsonb "preferences", default: "{}", null: false t.string "api_access_token" t.index ["created_by_id"], name: "index_projects_on_created_by_id" t.index ["updated_by_id"], name: "index_projects_on_updated_by_id" @@ -1507,8 +1507,8 @@ create_table "protocol_relationships", id: :serial, force: :cascade do |t| t.integer "protocol_id", null: false - t.integer "protocol_relationship_object_id", null: false t.string "protocol_relationship_object_type", null: false + t.integer "protocol_relationship_object_id", null: false t.integer "position", null: false t.integer "created_by_id", null: false t.integer "updated_by_id", null: false @@ -1766,8 +1766,8 @@ t.string "boundary_finder", null: false t.boolean "has_border", null: false t.string "layout", null: false - t.jsonb "metadata_map", default: {}, null: false - t.jsonb "specimen_coordinates", default: {}, null: false + t.jsonb "metadata_map", default: "{}", null: false + t.jsonb "specimen_coordinates", default: "{}", null: false t.integer "project_id", null: false t.integer "created_by_id", null: false t.integer "updated_by_id", null: false diff --git a/lib/queries/asserted_distribution/filter.rb b/lib/queries/asserted_distribution/filter.rb index 98da3b9d2b..29c9a26451 100644 --- a/lib/queries/asserted_distribution/filter.rb +++ b/lib/queries/asserted_distribution/filter.rb @@ -33,7 +33,7 @@ class Filter < Query::Filter # @return [Array] attr_accessor :otu_id - # @param otu_id [Array, Integer, String] + # @param geographic_area_id [Array, Integer, String] # @return [Array] attr_accessor :geographic_area_id @@ -49,12 +49,12 @@ class Filter < Query::Filter attr_accessor :geo_json # @return [Boolean, nil] + # true - Return AssertedDistributions where the OTU is asserted as present according to the Source + # false - Return AssertedDistributions where the OTU is asserted as absent according to the Source # nil - both - # true - only 't' - # false - only 'f' attr_accessor :presence - # @return Array + # @return [Array] # @param [taxon name ids, nil] # all Otus matching these taxon names attr_accessor :taxon_name_id @@ -119,7 +119,6 @@ def wkt_facet end def from_wkt(wkt_shape) - i = ::GeographicItem.joins(:geographic_areas).where(::GeographicItem.contained_by_wkt_sql(wkt_shape)) j = ::GeographicArea.joins(:geographic_items).where(geographic_items: i) @@ -213,7 +212,7 @@ def taxon_name_id_facet ::AssertedDistribution.joins(:otu).joins(j.join_sources).where(z) else - ::AssertedDistribution.joins(:otu).where(otus: {taxon_name_id: taxon_name_id}) + ::AssertedDistribution.joins(:otu).where(otus: {taxon_name_id:}) end end @@ -241,14 +240,14 @@ def biological_association_query_facet s = 'WITH query_ad_ba AS (' + biological_association_query.all.to_sql + ') ' a = ::AssertedDistribution - .joins("JOIN query_ad_ba as query_ad_ba1 on asserted_distributions.otu_id = query_ad_ba1.biological_association_subject_id AND query_ad_ba1.biological_association_subject_type = 'Otu'").to_sql + .joins("JOIN query_ad_ba as query_ad_ba1 on asserted_distributions.otu_id = query_ad_ba1.biological_association_subject_id AND query_ad_ba1.biological_association_subject_type = 'Otu'") b = ::AssertedDistribution - .joins("JOIN query_ad_ba as query_ad_ba2 on asserted_distributions.otu_id = query_ad_ba2.biological_association_object_id AND query_ad_ba2.biological_association_object_type = 'Otu'").to_sql + .joins("JOIN query_ad_ba as query_ad_ba2 on asserted_distributions.otu_id = query_ad_ba2.biological_association_object_id AND query_ad_ba2.biological_association_object_type = 'Otu'") - s << ::AssertedDistribution.from("((#{a}) UNION (#{b})) as asserted_distributions").to_sql + s << referenced_klass_union([a,b]).to_sql - ::AssertedDistribution.from('(' + s + ') as asserted_distributions') + ::AssertedDistribution.from('(' + s + ') as asserted_distributions').distinct end def and_clauses diff --git a/lib/queries/biological_association/filter.rb b/lib/queries/biological_association/filter.rb index 3cac612738..4407f56830 100644 --- a/lib/queries/biological_association/filter.rb +++ b/lib/queries/biological_association/filter.rb @@ -584,15 +584,28 @@ def collecting_event_query_facet def otu_query_facet return nil if otu_query.nil? s = 'WITH query_otu_ba AS (' + otu_query.all.to_sql + ') ' - ::BiologicalAssociation a = ::BiologicalAssociation - .joins("JOIN query_otu_ba as query_otu_ba1 on biological_associations.biological_association_subject_id = query_otu_ba1.id AND biological_associations.biological_association_subject_type = 'Otu'").to_sql + .joins("JOIN query_otu_ba as query_otu_ba1 on biological_associations.biological_association_subject_id = query_otu_ba1.id AND biological_associations.biological_association_subject_type = 'Otu'") b = ::BiologicalAssociation - .joins("JOIN query_otu_ba as query_otu_ba2 on biological_associations.biological_association_object_id = query_otu_ba2.id AND biological_associations.biological_association_object_type = 'Otu'").to_sql + .joins("JOIN query_otu_ba as query_otu_ba2 on biological_associations.biological_association_object_id = query_otu_ba2.id AND biological_associations.biological_association_object_type = 'Otu'") - s << ::BiologicalAssociation.from("((#{a} UNION (#{b})) as biological_associations").to_sql + s << referenced_klass_union([a,b]).to_sql + ::BiologicalAssociation.from('(' + s + ') as biological_associations') + end + + def asserted_distribution_query_facet + return nil if asserted_distribution_query.nil? + s = 'WITH query_ad_ba AS (' + asserted_distribution_query.all.to_sql + ') ' + + a = ::BiologicalAssociation + .joins("JOIN query_ad_ba as query_ad_ba1 on biological_associations.biological_association_subject_id = query_ad_ba1.otu_id AND biological_associations.biological_association_subject_type = 'Otu'") + + b = ::BiologicalAssociation + .joins("JOIN query_ad_ba as query_ad_ba2 on biological_associations.biological_association_object_id = query_ad_ba2.otu_id AND biological_associations.biological_association_object_type = 'Otu'") + + s << referenced_klass_union([a,b]).to_sql ::BiologicalAssociation.from('(' + s + ') as biological_associations') end @@ -601,12 +614,12 @@ def collection_object_query_facet s = 'WITH query_co_ba AS (' + collection_object_query.all.to_sql + ') ' a = ::BiologicalAssociation - .joins("JOIN query_co_ba as query_co_ba1 on biological_associations.biological_association_subject_id = query_co_ba1.id AND biological_associations.biological_association_subject_type = 'CollectionObject'").to_sql + .joins("JOIN query_co_ba as query_co_ba1 on biological_associations.biological_association_subject_id = query_co_ba1.id AND biological_associations.biological_association_subject_type = 'CollectionObject'") b = ::BiologicalAssociation - .joins("JOIN query_co_ba as query_co_ba2 on biological_associations.biological_association_object_id = query_co_ba2.id AND biological_associations.biological_association_object_type = 'CollectionObject'").to_sql + .joins("JOIN query_co_ba as query_co_ba2 on biological_associations.biological_association_object_id = query_co_ba2.id AND biological_associations.biological_association_object_type = 'CollectionObject'") - s << ::BiologicalAssociation.from('(' + [a,b].collect{|q| "(#{q})"}.join(' UNION ') + ') as biological_associations').to_sql + s << referenced_klass_union([a,b]).to_sql ::BiologicalAssociation.from('(' + s + ') as biological_associations') end @@ -620,12 +633,10 @@ def taxon_name_query_facet a = ::BiologicalAssociation .joins("JOIN otus on otus.id = biological_associations.biological_association_subject_id AND biological_associations.biological_association_subject_type = 'Otu'") .joins('JOIN query_tn_ba as query_tn_ba1 on otus.taxon_name_id = query_tn_ba1.id') - .to_sql b = ::BiologicalAssociation .joins("JOIN otus on otus.id = biological_associations.biological_association_object_id AND biological_associations.biological_association_object_type = 'Otu'") .joins('JOIN query_tn_ba as query_tn_ba2 on otus.taxon_name_id = query_tn_ba2.id') - .to_sql c = ::BiologicalAssociation .joins("JOIN collection_objects on collection_objects.id = biological_associations.biological_association_subject_id AND biological_associations.biological_association_subject_type = 'CollectionObject'") @@ -633,7 +644,6 @@ def taxon_name_query_facet .joins('JOIN otus on otus.id = taxon_determinations.otu_id') .joins('JOIN query_tn_ba as query_tn_ba3 on otus.taxon_name_id = query_tn_ba3.id') .where('taxon_determinations.position = 1') - .to_sql d = ::BiologicalAssociation .joins("JOIN collection_objects on collection_objects.id = biological_associations.biological_association_object_id AND biological_associations.biological_association_object_type = 'CollectionObject'") @@ -641,9 +651,8 @@ def taxon_name_query_facet .joins('JOIN otus on otus.id = taxon_determinations.otu_id') .joins('JOIN query_tn_ba as query_tn_ba4 on otus.taxon_name_id = query_tn_ba4.id') .where('taxon_determinations.position = 1') - .to_sql - s << ::BiologicalAssociation.from('(' + [a,b,c,d].collect{|q| "(#{q})"}.join(' UNION ') + ') as biological_associations').to_sql + s << referenced_klass_union([a,b,c,d]).to_sql ::BiologicalAssociation.from('(' + s + ') as biological_associations') end @@ -662,6 +671,7 @@ def and_clauses def merge_clauses [ + asserted_distribution_query_facet, collecting_event_query_facet, collection_object_query_facet, otu_query_facet, diff --git a/lib/queries/collecting_event/filter.rb b/lib/queries/collecting_event/filter.rb index d092b0a183..4081cfc18f 100644 --- a/lib/queries/collecting_event/filter.rb +++ b/lib/queries/collecting_event/filter.rb @@ -106,8 +106,8 @@ def self.base_params # @return [Boolean] # @param collector_id_or [String] - # 'true' - all ids treated as "or" - # 'false', nil - all ids treated as "and" + # `false`, nil - treat the ids in collector_id as "or" + # 'true' - treat the ids in collector_id as "and" (only CollectingEvent with all and only all of collector_id will match) attr_accessor :collector_id_or # @param collection_objects [String, nil] diff --git a/lib/queries/collection_object/filter.rb b/lib/queries/collection_object/filter.rb index c31c8f3a09..267a590744 100644 --- a/lib/queries/collection_object/filter.rb +++ b/lib/queries/collection_object/filter.rb @@ -240,8 +240,8 @@ class Filter < Query::Filter # @return [Boolean] # @param determiner_id_or [String, nil] - # `false`, nil - treat ids as "or" - # 'true' - treat ids as "and" (only collection objects with all and only all will match) + # `false`, nil - treat the ids in determiner_id as "or" + # 'true' - treat the ids in determiner_id as "and" (only collection objects with all and only all will match) attr_accessor :determiner_id_or # @return [String, nil] @@ -289,6 +289,7 @@ class Filter < Query::Filter attr_accessor :determiner_name_regex # @return Array + # match all CollectionObjects that are the origin of these Extracts attr_accessor :extract_id # @return Boolean @@ -320,10 +321,10 @@ def initialize(query_params) @collectors = boolean_param(params, :collectors) @collecting_event_id = params[:collecting_event_id] @collection_object_id = params[:collection_object_id] - @collection_object_type = params[:collection_object_type].blank? ? nil : params[:collection_object_type] + @collection_object_type = (params[:collection_object_type].presence) @current_determinations = boolean_param(params, :current_determinations) @current_repository = boolean_param(params, :current_repository) - @current_repository_id = params[:current_repository_id].blank? ? nil : params[:current_repository_id] + @current_repository_id = (params[:current_repository_id].presence) @dates = boolean_param(params, :dates) @descendants = boolean_param(params, :descendants) @determiners = boolean_param(params, :determiners) @@ -347,12 +348,12 @@ def initialize(query_params) @preparation_type = boolean_param(params, :preparation_type) @preparation_type_id = params[:preparation_type_id] @repository = boolean_param(params, :repository) - @repository_id = params[:repository_id].blank? ? nil : params[:repository_id] - @sled_image_id = params[:sled_image_id].blank? ? nil : params[:sled_image_id] + @repository_id = (params[:repository_id].presence) + @sled_image_id = (params[:sled_image_id].presence) @taxon_determinations = boolean_param(params, :taxon_determinations) @taxon_name_id = params[:taxon_name_id] @type_material = boolean_param(params, :type_material) - @type_specimen_taxon_name_id = params[:type_specimen_taxon_name_id].blank? ? nil : params[:type_specimen_taxon_name_id] + @type_specimen_taxon_name_id = (params[:type_specimen_taxon_name_id].presence) @validity = boolean_param(params, :validity) @with_buffered_collecting_event = boolean_param(params, :with_buffered_collecting_event) @with_buffered_determinations = boolean_param(params, :with_buffered_determinations) @@ -462,7 +463,7 @@ def determiner_facet o = ::TaxonDetermination.arel_table r = ::Role.arel_table - a = o.alias("a_det__") + a = o.alias('a_det__') b = o.project(a[Arel.star]).from(a) c = r.alias('det_r1') @@ -599,7 +600,7 @@ def geographic_area_facet def biocuration_facet return nil if biocuration_class_id.empty? ::CollectionObject::BiologicalCollectionObject.joins(:biocuration_classifications) - .where(biocuration_classifications: {biocuration_class_id: biocuration_class_id}) + .where(biocuration_classifications: {biocuration_class_id:}) end def loan_facet @@ -614,7 +615,7 @@ def type_facet def sled_image_facet return nil if sled_image_id.nil? - ::CollectionObject::BiologicalCollectionObject.joins(:depictions).where("depictions.sled_image_id = ?", sled_image_id) + ::CollectionObject::BiologicalCollectionObject.joins(:depictions).where('depictions.sled_image_id = ?', sled_image_id) end def biological_relationship_id_facet @@ -752,7 +753,7 @@ def taxon_name_id_facet else q = ::CollectionObject.joins(taxon_determinations: [:otu]) - .where(otus: {taxon_name_id: taxon_name_id}) + .where(otus: {taxon_name_id:}) if current_determinations q = q.where(taxon_determinations: {position: 1}) diff --git a/lib/queries/concerns/protocols.rb b/lib/queries/concerns/protocols.rb index 1c77fe1d31..f06a2dae71 100644 --- a/lib/queries/concerns/protocols.rb +++ b/lib/queries/concerns/protocols.rb @@ -4,13 +4,13 @@ module Queries::Concerns::Protocols extend ActiveSupport::Concern - def self.params + def self.params [ :protocols, :protocol_id_or, :protocol_id_and, - :protocol_id, # TODO: unused? or maybe in polymorphics setters!! - protocol_id: [], # TODO: unused? or maybe in polymorphics setters!! + :protocol_id, # TODO: unused? or maybe in polymorphics setters!! + protocol_id: [], # TODO: unused? or maybe in polymorphics setters!! protocol_id_or: [], protocol_id_and: [], ] @@ -18,15 +18,20 @@ def self.params included do # @return [Array] - # @params protocol_id_and [:protocol_id_and | [protocol_id_and, .. ] ] + # @params protocol_id_and + # match any objects linked to all Protocols referenced here attr_accessor :protocol_id_and # @return [Array] - # @params protocol_id_or [:protocol_id_or | [protocol_id_or, .. ] ] + # @params keyword_id_or + # match any objects linked to any Protocol referenced here attr_accessor :protocol_id_or # @return [Boolean, nil] # @params protocols ['true', 'false', nil] + # true - return objects that reference any Protocol + # false - return objects that reference no Protocol + # nil - ignored attr_accessor :protocols def protocol_id_and @@ -81,7 +86,7 @@ def self.merge_clauses :protocol_id_facet, :protocols_facet, ] - end + end private @@ -92,7 +97,7 @@ def matching_protocol_id_or t = ::ProtocolRelationship.arel_table w = t[:protocol_relationship_object_id].eq(table[:id]).and( t[:protocol_relationship_object_type].eq(table.name.classify)) - w = w.and( t[:protocol_id].eq_any(protocol_id_or) ) if protocol_id_or.any? + w = w.and( t[:protocol_id].eq_any(protocol_id_or) ) if protocol_id_or.any? k.where( ::ProtocolRelationship.where(w).arel.exists ) end diff --git a/lib/queries/concerns/tags.rb b/lib/queries/concerns/tags.rb index c08615a3b5..528cd1f167 100644 --- a/lib/queries/concerns/tags.rb +++ b/lib/queries/concerns/tags.rb @@ -7,7 +7,7 @@ module Queries::Concerns::Tags extend ActiveSupport::Concern def self.params - [ + [ :keyword_id_and, :keyword_id_or, :tags, @@ -18,11 +18,13 @@ def self.params included do # @return [Array] - # @params keyword_id_and [:keyword_id_and | [keyword_id_and, .. ] ] + # @params keyword_id_and + # match all objects tagged with all of the keywords referenced in this array attr_accessor :keyword_id_and # @return [Array] - # @params keyword_id_or [:keyword_id_or | [keyword_id_or, .. ] ] + # @params keyword_id_or + # match all objects tagged with any of the keywords referenced in this array attr_accessor :keyword_id_or # @return [Boolean, nil] @@ -61,7 +63,7 @@ def keyword_id_or end # @return [Arel::Table] - def tag_table + def tag_table ::Tag.arel_table end @@ -99,14 +101,14 @@ def tags_facet .where(tags: {id: nil}) end end - + def matching_keyword_id_or return nil if keyword_id_or.empty? k = table.name.classify.safe_constantize t = ::Tag.arel_table w = t[:tag_object_id].eq(table[:id]).and( t[:tag_object_type].eq(table.name.classify)) - w = w.and( t[:keyword_id].eq_any(keyword_id_or) ) if keyword_id_or.any? + w = w.and( t[:keyword_id].eq_any(keyword_id_or) ) if keyword_id_or.any? k.where( ::Tag.where(w).arel.exists ) end @@ -144,4 +146,4 @@ def matching_keyword_id_and k.joins(Arel::Nodes::InnerJoin.new(b, Arel::Nodes::On.new(b[:id].eq(table[:id])))) end -end \ No newline at end of file +end diff --git a/lib/queries/image/filter.rb b/lib/queries/image/filter.rb index fcbfa1eb1b..e06db08dd6 100644 --- a/lib/queries/image/filter.rb +++ b/lib/queries/image/filter.rb @@ -22,8 +22,6 @@ class Filter < Query::Filter collection_object_id: [], depiction_object_type: [], image_id: [], - keyword_id_and: [], - keyword_id_or: [], otu_id: [], otu_scope: [], sled_image_id: [], @@ -72,7 +70,7 @@ class Filter < Query::Filter # # !! Must be used with an otu_id !! # @param otu_scope - # One or more of: + # One or more of: # :all (default, includes all below) # # :otu (those on the OTU) @@ -205,13 +203,13 @@ def biocuration_facet return nil if biocuration_class_id.empty? ::Image.joins(collection_objects: [:depictions]).merge( ::CollectionObject::BiologicalCollectionObject.joins(:biocuration_classifications) - .where(biocuration_classifications: {biocuration_class_id: biocuration_class_id}) + .where(biocuration_classifications: {biocuration_class_id:}) ) end def depiction_object_type_facet return nil if depiction_object_type.empty? - ::Image.joins(:depictions).where(depictions: {depiction_object_type: depiction_object_type}) + ::Image.joins(:depictions).where(depictions: {depiction_object_type:}) end def depictions_facet diff --git a/lib/queries/otu/filter.rb b/lib/queries/otu/filter.rb index a824c9c058..385fff8efa 100644 --- a/lib/queries/otu/filter.rb +++ b/lib/queries/otu/filter.rb @@ -419,7 +419,7 @@ def asserted_distribution_query_facet .joins('JOIN query_ad_otus as query_ad_otus1 on otus.id = query_ad_otus1.otu_id') .to_sql - ::Otu.from('(' + s + ') as otus') + ::Otu.from('(' + s + ') as otus').distinct end def content_query_facet @@ -429,7 +429,7 @@ def content_query_facet .joins('JOIN query_con_otus as query_con_otus1 on otus.id = query_con_otus1.otu_id') .to_sql - ::Otu.from('(' + s + ') as otus') + ::Otu.from('(' + s + ') as otus').distinct end def biological_association_query_facet @@ -437,12 +437,12 @@ def biological_association_query_facet s = 'WITH query_ba_otu AS (' + biological_association_query.all.to_sql + ') ' a = ::Otu - .joins("JOIN query_ba_otu as query_ba_otu1 on otus.id = query_ba_otu1.biological_association_subject_id AND query_ba_otu1.biological_association_subject_type = 'Otu'").to_sql + .joins("JOIN query_ba_otu as query_ba_otu1 on otus.id = query_ba_otu1.biological_association_subject_id AND query_ba_otu1.biological_association_subject_type = 'Otu'") b = ::Otu - .joins("JOIN query_ba_otu as query_ba_otu2 on otus.id = query_ba_otu2.biological_association_object_id AND query_ba_otu2.biological_association_object_type = 'Otu'").to_sql + .joins("JOIN query_ba_otu as query_ba_otu2 on otus.id = query_ba_otu2.biological_association_object_id AND query_ba_otu2.biological_association_object_type = 'Otu'") - s << ::Otu.from("((#{a}) UNION (#{b})) as otus").to_sql + s << referenced_klass_union([a,b]).to_sql ::Otu.from('(' + s + ') as otus') end @@ -455,7 +455,7 @@ def collection_object_query_facet .joins('JOIN query_co_otus as query_co_otus1 on collection_objects.id = query_co_otus1.id') .to_sql - ::Otu.from('(' + s + ') as otus') + ::Otu.from('(' + s + ') as otus').distinct end def collecting_event_query_facet @@ -466,7 +466,7 @@ def collecting_event_query_facet .joins('JOIN query_ce_otus as query_ce_otus1 on collecting_events.id = query_ce_otus1.id') .to_sql - ::Otu.from('(' + s + ') as otus') + ::Otu.from('(' + s + ') as otus').distinct end def extract_query_facet @@ -477,7 +477,7 @@ def extract_query_facet .joins("JOIN query_ex_otus as query_ex_otus1 on origin_relationships.new_object_id = query_ex_otus1.id and origin_relationships.new_object_type = 'Extract'") .to_sql - ::Otu.from('(' + s + ') as otus') + ::Otu.from('(' + s + ') as otus').distinct end def taxon_name_query_facet @@ -488,7 +488,7 @@ def taxon_name_query_facet .joins('JOIN query_taxon_names as query_taxon_names1 on otus.taxon_name_id = query_taxon_names1.id') .to_sql - ::Otu.from('(' + s + ') as otus') + ::Otu.from('(' + s + ') as otus').distinct end def descriptor_query_facet @@ -499,7 +499,7 @@ def descriptor_query_facet .joins('JOIN query_de_otus as query_de_otus1 on observations.descriptor_id = query_de_otus1.id') .to_sql - ::Otu.from('(' + s + ') as otus') + ::Otu.from('(' + s + ') as otus').distinct end def loan_query_facet @@ -508,15 +508,13 @@ def loan_query_facet a = ::Otu.joins(:loan_items) .joins('JOIN query_loan_otus as query_loan_otus1 on loan_items.loan_id = query_loan_otus1.id') - .to_sql b = ::Otu.joins(collection_objects: [:loan_items]) .joins('JOIN query_loan_otus as query_loan_otus1 on loan_items.loan_id = query_loan_otus1.id') - .to_sql - s << ::Otu.from("((#{a}) UNION (#{b})) as otus").to_sql + s << referenced_klass_union([a,b]).to_sql - ::Otu.from('(' + s + ') as otus') + ::Otu.from('(' + s + ') as otus').distinct end def observation_query_facet diff --git a/lib/queries/person/autocomplete.rb b/lib/queries/person/autocomplete.rb index 3cff1cac2d..3fd704b0c3 100644 --- a/lib/queries/person/autocomplete.rb +++ b/lib/queries/person/autocomplete.rb @@ -138,13 +138,6 @@ def autocomplete .where("roles.project_id IN (#{pr_id}) OR project_sources.project_id IN (#{pr_id}) OR (roles.project_id NOT IN (#{pr_id}) AND project_sources.project_id NOT IN (#{pr_id})) OR (roles.project_id IS NULL AND project_sources.project_id IS NULL)") .group('people.id') .order('in_project, use_count DESC') - elsif role_type.present? - a = a.left_outer_joins(:roles) - .joins("LEFT OUTER JOIN sources ON roles.role_object_id = sources.id AND roles.role_object_type = 'Source'") - .joins('LEFT OUTER JOIN project_sources ON sources.id = project_sources.source_id') - .select("people.*, COUNT(roles.id) AS use_count, CASE WHEN MAX(roles.project_id) IN (#{pr_id}) THEN MAX(roles.project_id) ELSE MAX(project_sources.project_id) END AS in_project") - .group('people.id') - .order('in_project_id, use_count DESC') end end diff --git a/lib/queries/person/filter.rb b/lib/queries/person/filter.rb index 6728f99acf..6fee62dc5f 100644 --- a/lib/queries/person/filter.rb +++ b/lib/queries/person/filter.rb @@ -31,8 +31,6 @@ class Filter < Query::Filter exact: [], except_project_id: [], except_role: [], - keyword_id_and: [], - keyword_id_or: [], only_project_id: [], person_id: [], role: [], @@ -276,7 +274,7 @@ def regex_facet end def name_facet - return nil if name.nil? || !levenshtein_cuttoff.blank? + return nil if name.nil? || levenshtein_cuttoff.present? if exact.include?('name') table[:cached].eq(name) else @@ -285,7 +283,7 @@ def name_facet end def last_name_starts_with_facet - return nil if last_name_starts_with.blank? || !levenshtein_cuttoff.blank? + return nil if last_name_starts_with.blank? || levenshtein_cuttoff.present? table[:last_name].matches(last_name_starts_with + '%') end @@ -363,7 +361,7 @@ def without_facet end def levenshtein_facet - return nil unless levenshtein_cuttoff && (!name.blank?) + return nil unless levenshtein_cuttoff && (name.present?) ::Person.where( levenshtein_distance(:cached, name).lteq(levenshtein_cuttoff).to_sql ) diff --git a/lib/queries/query/filter.rb b/lib/queries/query/filter.rb index 8890d87b5e..6327270d87 100644 --- a/lib/queries/query/filter.rb +++ b/lib/queries/query/filter.rb @@ -34,7 +34,7 @@ class Query::Filter < Queries::Query # This is read as :to <- [:from1, from2...] ]. SUBQUERIES = { asserted_distribution: [:source, :otu, :biological_association, :taxon_name], - biological_association: [:source, :collecting_event, :otu, :collection_object, :taxon_name], + biological_association: [:source, :collecting_event, :otu, :collection_object, :taxon_name, :asserted_distribution], collecting_event: [:source, :collection_object, :biological_association, :otu, :image, :taxon_name], collection_object: [:source, :loan, :otu, :taxon_name, :collecting_event, :biological_association, :extract, :image, :observation], content: [:source, :otu, :taxon_name, :image], diff --git a/lib/queries/source/filter.rb b/lib/queries/source/filter.rb index dfb91cc2ef..e0636f75a5 100644 --- a/lib/queries/source/filter.rb +++ b/lib/queries/source/filter.rb @@ -2,14 +2,14 @@ module Queries module Source class Filter < Query::Filter - ATTRIBUTES = (::Source.core_attributes - %w{bibtex_type title author}).map(&:to_sym).freeze + ATTRIBUTES = (::Source.core_attributes - %w{bibtex_type title author}).map(&:to_sym).freeze include Queries::Concerns::Attributes include Queries::Concerns::Empty include Queries::Concerns::Notes include Queries::Concerns::Tags - + PARAMS = [ *ATTRIBUTES, :source_id, @@ -38,8 +38,6 @@ class Filter < Query::Filter bibtex_type: [], citation_object_type: [], empty: [], - keyword_id_and: [], - keyword_id_or: [], not_empty: [], serial_id: [], source_id: [], @@ -71,6 +69,8 @@ class Filter < Query::Filter attr_accessor :author_id # @params author [Boolean, nil] + # `false`, nil - treat the ids in author_id as "or" + # 'true' - treat the ids in author_id as "and" (only Sources with all and only all will match) attr_accessor :author_id_or # @params author [Array of Integer, Topic#id] @@ -255,7 +255,7 @@ def source_type_facet def year_facet return nil if year_start.blank? - if year_start && !year_end.blank? + if year_start && year_end.present? table[:year].gteq(year_start) .and(table[:year].lteq(year_end)) else # only start @@ -272,7 +272,7 @@ def author_id_facet o = table r = ::Role.arel_table - a = o.alias("a_") + a = o.alias('a_') b = o.project(a[Arel.star]).from(a) c = r.alias('r1') @@ -297,7 +297,7 @@ def author_id_facet def topic_id_facet return nil if topic_id.empty? - ::Source.joins(:citation_topics).where(citation_topics: { topic_id: topic_id }).distinct + ::Source.joins(:citation_topics).where(citation_topics: { topic_id: }).distinct end def in_project_facet @@ -379,7 +379,7 @@ def serial_facet def citation_object_type_facet return nil if citation_object_type.empty? ::Source.joins(:citations) - .where(citations: {citation_object_type: citation_object_type}).distinct + .where(citations: {citation_object_type:}).distinct end def nomenclature_facet diff --git a/lib/queries/taxon_name/filter.rb b/lib/queries/taxon_name/filter.rb index 816646f72c..ec583182ab 100644 --- a/lib/queries/taxon_name/filter.rb +++ b/lib/queries/taxon_name/filter.rb @@ -228,7 +228,8 @@ class Filter < Query::Filter # @return [Boolean] # @param [String] - # 'true' + # `false`, nil - treat the ids in taxon_name_author_id as "or" (match any TaxonName with any of these authors) + # 'true' - treat the ids in taxon_name_author_id as "and" (only TaxonNames with all and only all will match) attr_accessor :taxon_name_author_id_or # @return [String, nil] @@ -278,7 +279,7 @@ def initialize(query_params) @parent_id = params[:parent_id] @rank = params[:rank] @sort = params[:sort] - @taxon_name_author_id = params[:taxon_name_author_ids] + @taxon_name_author_id = params[:taxon_name_author_id] @taxon_name_author_id_or = boolean_param(params, :taxon_name_author_id_or) @taxon_name_classification = params[:taxon_name_classification] || [] @taxon_name_id = params[:taxon_name_id] @@ -366,11 +367,11 @@ def nomenclature_code def geo_json_facet return nil if geo_json.nil? - otus = ::Queries::Otu::Filter.new(geo_json: geo_json).all - collection_objects = ::Queries::CollectionObject::Filter.new(geo_json: geo_json).all + otus = ::Queries::Otu::Filter.new(geo_json:).all + collection_objects = ::Queries::CollectionObject::Filter.new(geo_json:).all a = ::TaxonName.joins(:taxon_taxon_determinations).where(taxon_determinations: { biological_collection_object: collection_objects} ) - b = ::TaxonName.joins(:otus).where(otus: otus) + b = ::TaxonName.joins(:otus).where(otus:) ::TaxonName.from("((#{a.to_sql}) UNION (#{b.to_sql})) as taxon_names") end @@ -378,11 +379,11 @@ def geo_json_facet def not_specified_facet return nil if not_specified.nil? if not_specified - ::TaxonName.where(table[:cached].matches("%NOT SPECIFIED%").or( - table[:cached_original_combination].matches("%NOT SPECIFIED%"))) + ::TaxonName.where(table[:cached].matches('%NOT SPECIFIED%').or( + table[:cached_original_combination].matches('%NOT SPECIFIED%'))) else - ::TaxonName.where(table[:cached].does_not_match("%NOT SPECIFIED%").and( - table[:cached_original_combination].does_not_match("%NOT SPECIFIED%"))) + ::TaxonName.where(table[:cached].does_not_match('%NOT SPECIFIED%').and( + table[:cached_original_combination].does_not_match('%NOT SPECIFIED%'))) end end @@ -504,7 +505,7 @@ def taxon_name_author_id_facet o = table r = ::Role.arel_table - a = o.alias("a_") + a = o.alias('a_') b = o.project(a[Arel.star]).from(a) c = r.alias('r1') @@ -517,7 +518,7 @@ def taxon_name_author_id_facet ) e = c[:id].not_eq(nil) - f = c[:person_id].eq_any(taxon_name_author_ids) + f = c[:person_id].eq_any(taxon_name_author_id) b = b.where(e.and(f)) b = b.group(a['id']) @@ -626,7 +627,7 @@ def collecting_event_id_facet return nil if collecting_event_id.empty? ::TaxonName .joins(:collection_objects) - .where(collection_objects: {collecting_event_id: collecting_event_id}) + .where(collection_objects: {collecting_event_id:}) end def combinations_facet diff --git a/lib/queries/type_material/autocomplete.rb b/lib/queries/type_material/autocomplete.rb new file mode 100644 index 0000000000..9c05e6c5fd --- /dev/null +++ b/lib/queries/type_material/autocomplete.rb @@ -0,0 +1,38 @@ +module Queries + module TypeMaterial + class Autocomplete < Query::Autocomplete + + # @return [String] + def where_sql + with_project_id.and(with_cached_taxon_name.or(with_cached_identifier)).to_sql + end + + # @return [Scope] + def all + ::TypeMaterial.includes(:protonym, collection_object: [:identifiers] ).where(where_sql).references(:taxon_names).limit(dynamic_limit).all + end + + # @return [Arel::Table] + def taxon_name_table + ::TaxonName.arel_table + end + + # @return [Arel::Table] + def identifier_table + ::Identifier.arel_table + end + + # source, material, prototonym + # @return [Arel::Nodes::Matches] + def with_cached_taxon_name + taxon_name_table[:cached].matches_any(terms) + end + + # @return [Arel::Nodes::Matches] + def with_cached_identifier + identifier_table[:cached].matches_any(terms) + end + + end + end +end \ No newline at end of file diff --git a/lib/taxonworks/version.rb b/lib/taxonworks/version.rb index 5f429b379a..5c50136335 100644 --- a/lib/taxonworks/version.rb +++ b/lib/taxonworks/version.rb @@ -1,3 +1,3 @@ module Taxonworks - VERSION = "0.31.1" + VERSION = "0.31.2" end