// ResourceListParams expresses which results are requested in a
// list/index API.
type ResourceListParams struct {
- Select []string `json:"select,omitempty"`
- Filters []Filter `json:"filters,omitempty"`
- Limit *int `json:"limit,omitempty"`
- Offset int `json:"offset,omitempty"`
- Order string `json:"order,omitempty"`
- Distinct bool `json:"distinct,omitempty"`
- Count bool `json:"count,omitempty"`
+ Select []string `json:"select,omitempty"`
+ Filters []Filter `json:"filters,omitempty"`
+ IncludeTrash bool `json:"include_trash,omitempty"`
+ Limit *int `json:"limit,omitempty"`
+ Offset int `json:"offset,omitempty"`
+ Order string `json:"order,omitempty"`
++ Distinct bool `json:"distinct,omitempty"`
++ Count bool `json:"count,omitempty"`
}
// A Filter restricts the set of records returned by a list/index API.
include CurrentApiClient
include ThemesForRails::ActionController
include LoadParam
+ include DbCurrentTime
respond_to :json
protect_from_forgery
theme :select_theme
- attr_accessor :resource_attrs
+ attr_writer :resource_attrs
+
+ MAX_UNIQUE_NAME_ATTEMPTS = 10
begin
rescue_from(Exception,
:with => :render_not_found)
end
+ def initialize *args
+ super
+ @object = nil
+ @objects = nil
+ @offset = nil
+ @limit = nil
+ @select = nil
+ @distinct = nil
+ @response_resource_name = nil
+ @attrs = nil
+ end
+
def default_url_options
if Rails.configuration.host
{:host => Rails.configuration.host}
if @object.respond_to? :name and params[:ensure_unique_name]
# Record the original name. See below.
name_stem = @object.name
- counter = 1
+ retries = MAX_UNIQUE_NAME_ATTEMPTS
+ else
+ retries = 0
end
begin
@object.save!
rescue ActiveRecord::RecordNotUnique => rn
- raise unless params[:ensure_unique_name]
+ raise unless retries > 0
+ retries -= 1
# Dig into the error to determine if it is specifically calling out a
# (owner_uuid, name) uniqueness violation. In this specific case, and
detail = err.result.error_field(PG::Result::PG_DIAG_MESSAGE_DETAIL)
raise unless /^Key \(owner_uuid, name\)=\([a-z0-9]{5}-[a-z0-9]{5}-[a-z0-9]{15}, .*?\) already exists\./.match detail
- # OK, this exception really is just a unique name constraint
- # violation, and we've been asked to ensure_unique_name.
- counter += 1
@object.uuid = nil
- @object.name = "#{name_stem} (#{counter})"
- redo
- end while false
+
+ new_name = "#{name_stem} (#{db_current_time.utc.iso8601(3)})"
+ if new_name == @object.name
+ # If the database is fast enough to do two attempts in the
+ # same millisecond, we need to wait to ensure we try a
+ # different timestamp on each attempt.
+ sleep 0.002
+ new_name = "#{name_stem} (#{db_current_time.utc.iso8601(3)})"
+ end
+ @object.name = new_name
+ retry
+ end
show
end
end
def find_object_by_uuid
- if params[:id] and params[:id].match /\D/
+ if params[:id] and params[:id].match(/\D/)
params[:uuid] = params.delete :id
end
@where = { uuid: params[:uuid] }
:limit => @limit,
:items => @objects.as_api_response(nil, {select: @select})
}
- if @objects.respond_to? :except
- list[:items_available] = @objects.
- except(:limit).except(:offset).
- count(:id, distinct: true)
+ if params[:count].nil? || params[:count]
+ if @objects.respond_to? :except
+ list[:items_available] = @objects.
+ except(:limit).except(:offset).
+ count(:id, distinct: true)
+ end
end
list
end
distinct: { type: 'boolean', required: false },
limit: { type: 'integer', required: false, default: DEFAULT_LIMIT },
offset: { type: 'integer', required: false, default: 0 },
+ count: { type: 'boolean', required: false, default: true},
}
end
}
end
end
- super *opts
+ super(*opts)
end
def select_theme
if Rails.application.config.websocket_address
discovery[:websocketUrl] = Rails.application.config.websocket_address
elsif ENV['ARVADOS_WEBSOCKETS']
- discovery[:websocketUrl] = (root_url.sub /^http/, 'ws') + "websocket"
+ discovery[:websocketUrl] = root_url.sub(/^http/, 'ws') + "websocket"
end
ActiveRecord::Base.descendants.reject(&:abstract_class?).each do |k|
},
select: {
type: "array",
- description: "Select which fields to return",
+ description: "Select which fields to return.",
location: "query"
},
distinct: {
type: "boolean",
- description: "Return each distinct object",
+ description: "Return each distinct object.",
+ location: "query"
+ },
+ count: {
+ type: "boolean",
+ description: "Count items_available.",
+ default: "true",
location: "query"
}
},
method = d_methods[action.to_sym]
end
if ctl_class.respond_to? "_#{action}_requires_parameters".to_sym
- ctl_class.send("_#{action}_requires_parameters".to_sym).each do |k, v|
+ ctl_class.send("_#{action}_requires_parameters".to_sym).each do |l, v|
if v.is_a? Hash
- method[:parameters][k] = v
+ method[:parameters][l] = v
else
- method[:parameters][k] = {}
+ method[:parameters][l] = {}
end
- if !method[:parameters][k][:default].nil?
+ if !method[:parameters][l][:default].nil?
# The JAVA SDK is sensitive to all values being strings
- method[:parameters][k][:default] = method[:parameters][k][:default].to_s
+ method[:parameters][l][:default] = method[:parameters][l][:default].to_s
end
- method[:parameters][k][:type] ||= 'string'
- method[:parameters][k][:description] ||= ''
- method[:parameters][k][:location] = (route.segment_keys.include?(k) ? 'path' : 'query')
- if method[:parameters][k][:required].nil?
- method[:parameters][k][:required] = v != false
+ method[:parameters][l][:type] ||= 'string'
+ method[:parameters][l][:description] ||= ''
+ method[:parameters][l][:location] = (route.segment_keys.include?(l) ? 'path' : 'query')
+ if method[:parameters][l][:required].nil?
+ method[:parameters][l][:required] = v != false
end
end
end
var page arvados.CollectionList
var zero int
params.Limit = &zero
+ params.Count = true
err := c.RequestAndDecode(&page, "GET", "arvados/v1/collections", nil, params)
return page.ItemsAvailable, err
}
progress = func(_, _ int) {}
}
- expectCount, err := countCollections(c, arvados.ResourceListParams{})
+ expectCount, err := countCollections(c, arvados.ResourceListParams{
+ IncludeTrash: true,
+ })
if err != nil {
return err
}
limit = 1<<31 - 1
}
params := arvados.ResourceListParams{
- Limit: &limit,
- Order: "modified_at, uuid",
- Count: false,
- Select: []string{"uuid", "manifest_text", "modified_at", "portable_data_hash", "replication_desired"},
+ Limit: &limit,
+ Order: "modified_at, uuid",
++ Count: false,
+ Select: []string{"uuid", "unsigned_manifest_text", "modified_at", "portable_data_hash", "replication_desired"},
+ IncludeTrash: true,
}
var last arvados.Collection
var filterTime time.Time
}
progress(callCount, expectCount)
- if checkCount, err := countCollections(c, arvados.ResourceListParams{Filters: []arvados.Filter{{
- Attr: "modified_at",
- Operator: "<=",
- Operand: filterTime}}}); err != nil {
+ if checkCount, err := countCollections(c, arvados.ResourceListParams{
+ Filters: []arvados.Filter{{
+ Attr: "modified_at",
+ Operator: "<=",
+ Operand: filterTime}},
+ IncludeTrash: true,
+ }); err != nil {
return err
} else if callCount < checkCount {
return fmt.Errorf("Retrieved %d collections with modtime <= T=%q, but server now reports there are %d collections with modtime <= T", callCount, filterTime, checkCount)