Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 13 additions & 21 deletions +dj/Relvar.m
Original file line number Diff line number Diff line change
Expand Up @@ -343,40 +343,32 @@ function update(self, attrname, value)
% update(v2p.Mice & key, 'mouse_dob', '2011-01-01')
% update(v2p.Scan & key, 'lens') % set the value to NULL

assert(count(self)==1, 'Update is only allowed on one tuple at a time')
isNull = nargin<3;
assert(count(self)==1, 'Update is only allowed on one tuple at a time');
header = self.header;
ix = find(strcmp(attrname,header.names));
assert(numel(ix)==1, 'invalid attribute name')
assert(~header.attributes(ix).iskey, 'cannot update a key value. Use insert(..,''REPLACE'') instead')
assert(numel(ix)==1, 'invalid attribute name');
assert(~header.attributes(ix).iskey, ...
'cannot update a key value. Use insert(..,''REPLACE'') instead');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

beautifully handled

isNull = nargin<3 || (header.attributes(ix).isNumeric && isnan(value)) || ...
(~header.attributes(ix).isNumeric && ~ischar(value) && isempty(value));

switch true
case isNull
assert(header.attributes(ix).isnullable, ...
'attribute `%s` is not nullable.', attrname);
valueStr = 'NULL';
value = {};
case header.attributes(ix).isString
assert(dj.lib.isString(value), 'Value must be a string')
assert(dj.lib.isString(value), 'Value must be a string');
valueStr = '"{S}"';
value = {char(value)};
case header.attributes(ix).isBlob
if isempty(value) && header.attributes(ix).isnullable
valueStr = 'NULL';
value = {};
else
valueStr = '"{M}"';
value = {value};
end
valueStr = '"{M}"';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how is NULL handled here?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh, I see, it's already handled together for all attribute types.

value = {value};
case header.attributes(ix).isNumeric
assert(isscalar(value) && isnumeric(value), 'Numeric value must be scalar')
if isnan(value)
assert(header.attributes(ix).isnullable, ...
'attribute `%s` is not nullable. NaNs not allowed', attrname)
valueStr = 'NULL';
value = {};
else
valueStr = sprintf('%1.16g',value);
value = {};
end
valueStr = sprintf('%1.16g',value);
value = {};
otherwise
error 'invalid update command'
end
Expand Down
159 changes: 83 additions & 76 deletions +dj/createSchema.m
Original file line number Diff line number Diff line change
@@ -1,89 +1,96 @@
function createSchema(package,parentdir,db)
% DJ.CREATESCHEMA - interactively create a new DataJoint schema
%
% INPUT:
% (optional) package - name of the package to be associated with the schema
% (optional) parentdir - name of the dirctory where to create new package
% (optional) db - database name to associate with the schema

if nargin < 3
dbname = input('Enter database name >> ','s');
else
dbname = db;
end

if ~dbname
disp 'No database name entered. Quitting.'
elseif isempty(regexp(dbname,'^[a-z][a-z0-9_]*$','once'))
error 'Invalid database name. Begin with a letter, only lowercase alphanumerical and underscores.'
else
% create database
s = query(dj.conn, ...
sprintf('SELECT schema_name FROM information_schema.schemata WHERE schema_name = "%s"', dbname));

if ~isempty(s.schema_name)
disp 'database already exists'
% DJ.CREATESCHEMA - interactively create a new DataJoint schema
%
% INPUT:
% (optional) package - name of the package to be associated with the schema
% (optional) parentdir - name of the dirctory where to create new package
% (optional) db - database name to associate with the schema

if nargin < 3
dbname = input('Enter database name >> ','s');
else
query(dj.conn, sprintf('create schema %s',dbname))
disp 'database created'
dbname = db;
end

if nargin < 1
if usejava('desktop')
disp 'Please select a package folder. Opening UI...'
folder = uigetdir('./','Select a package folder');

if ~dbname
disp 'No database name entered. Quitting.'
elseif isempty(regexp(dbname,'^[a-z][a-z0-9_]*$','once'))
error(['Invalid database name. Begin with a letter, only lowercase alphanumerical and ' ...
'underscores.'])
else
% create database
s = query(dj.conn, ...
sprintf(['SELECT schema_name as `schema_name` ' ...
'FROM information_schema.schemata WHERE schema_name = "%s"'], dbname));

if ~isempty(s.schema_name)
disp 'database already exists'
else
folder = input('Enter package folder path >> ','s');
query(dj.conn, sprintf('create schema %s',dbname))
disp 'database created'
end
else
if nargin < 3

if nargin < 1
if usejava('desktop')
fprintf('Please select folder to create package %s in. Opening UI...\n', ['+', package])
folder = uigetdir('./', sprintf('Select folder to create package %s in', ['+', package]));
disp 'Please select a package folder. Opening UI...'
folder = uigetdir('./','Select a package folder');
else
folder = input('Enter parent folder path >> ','s');
folder = input('Enter package folder path >> ','s');
end
else
folder = parentdir;
end

if folder
folder = fullfile(folder, ['+', package]);
mkdir(folder)
end
end

if ~folder
disp 'No package selected. Cancelled.'
else
[filepath,package] = fileparts(folder);
if package(1)~='+'
error 'Package folders must start with a +'
if nargin < 3
if usejava('desktop')
fprintf('Please select folder to create package %s in. Opening UI...\n', ...
['+', package])
folder = uigetdir('./', sprintf('Select folder to create package %s in', ...
['+', package]));
else
folder = input('Enter parent folder path >> ','s');
end
else
folder = parentdir;
end

if folder
folder = fullfile(folder, ['+', package]);
mkdir(folder)
end
end
package = package(2:end); % discard +

% create the getSchema function
schemaFile = fullfile(folder,'getSchema.m');
if exist(schemaFile,'file')
fprintf('%s.getSchema.m already exists\n', package)

if ~folder
disp 'No package selected. Cancelled.'
else
f = fopen(schemaFile,'wt');
assert(-1 ~= f, 'Could not open %s', f)

fprintf(f,'function obj = getSchema\n');
fprintf(f,'persistent schemaObject\n');
fprintf(f,'if isempty(schemaObject)\n');
fprintf(f,' schemaObject = dj.Schema(dj.conn, ''%s'', ''%s'');\n', package, dbname);
fprintf(f,'end\n');
fprintf(f,'obj = schemaObject;\n');
fprintf(f,'end\n');
fclose(f);
end

% test that getSchema is on the path
whichpath = which(sprintf('%s.getSchema',package));
if isempty(whichpath)
warning('Could not open %s.getSchema. Ensure that %s is on the path', package, filepath)
[filepath,package] = fileparts(folder);
if package(1)~='+'
error 'Package folders must start with a +'
end
package = package(2:end); % discard +

% create the getSchema function
schemaFile = fullfile(folder,'getSchema.m');
if exist(schemaFile,'file')
fprintf('%s.getSchema.m already exists\n', package)
else
f = fopen(schemaFile,'wt');
assert(-1 ~= f, 'Could not open %s', f)

fprintf(f,'function obj = getSchema\n');
fprintf(f,'persistent schemaObject\n');
fprintf(f,'if isempty(schemaObject)\n');
fprintf(f,' schemaObject = dj.Schema(dj.conn, ''%s'', ''%s'');\n', ...
package, dbname);
fprintf(f,'end\n');
fprintf(f,'obj = schemaObject;\n');
fprintf(f,'end\n');
fclose(f);
end

% test that getSchema is on the path
whichpath = which(sprintf('%s.getSchema',package));
if isempty(whichpath)
warning('Could not open %s.getSchema. Ensure that %s is on the path', ...
package, filepath)
end
end
end
end
end
100 changes: 100 additions & 0 deletions +tests/+lib/compareVersions.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
function res = compareVersions(verArray, verComp)
% compareVersions - Semantic version comparison (greater than or equal)
%
% This function evaluates if an array of semantic versions is greater than
% or equal to a reference version.
%
% DISTRIBUTION:
% GitHub: https://github.com/guzman-raphael/compareVersions
% FileExchange: https://www.mathworks.com/matlabcentral/fileexchange/71849-compareversions
%
% res = compareVersions(verArray, verComp)
% INPUT:
% verArray: Cell array with the following conditions:
% - be of length >= 1,
% - contain only string elements, and
% - each element must be of length >= 1.
% verComp: String or Char array that verArray will compare against for
% greater than evaluation. Must be:
% - be of length >= 1, and
% - a string.
% OUTPUT:
% res: Logical array that identifies if each cell element in verArray
% is greater than or equal to verComp.
% TESTS:
% Tests included for reference. From root package directory,
% use command: runtests
%
% EXAMPLES:
% output = compareVersions({'3.2.4beta','9.5.2.1','8.0'}, '8.0.0'); %logical([0 1 1])
%
% NOTES:
% Tests included for reference. From root package directory,
% use command: runtests
%
% Tested: Matlab 9.5.0.944444 (R2018b) Linux
% Author: Raphael Guzman, DataJoint
%
% $License: MIT (use/copy/change/redistribute on own risk) $
% $File: compareVersions.m $
% History:
% 001: 2019-06-12 11:00, First version.
%
% OPEN BUGS:
% - None
res_n = length(verArray);
if ~res_n || max(cellfun(@(c) ~ischar(c) && ...
~isstring(c),verArray)) > 0 || min(cellfun('length',verArray)) == 0
msg = {
'compareVersions:Error:CellArray'
'Cell array to verify must:'
'- be of length >= 1,'
'- contain only string elements, and'
'- each element must be of length >= 1.'
};
error('compareVersions:Error:CellArray', sprintf('%s\n',msg{:}));
end
if ~ischar(verComp) && ~isstring(verComp) || length(verComp) == 0
msg = {
'compareVersions:Error:VersionRef'
'Version reference must:'
'- be of length >= 1, and'
'- a string.'
};
error('compareVersions:Error:VersionRef', sprintf('%s\n',msg{:}));
end
res = false(1, res_n);
for i = 1:res_n
shortVer = strsplit(verArray{i}, '.');
shortVer = cellfun(@(x) str2double(regexp(x,'\d*','Match')), shortVer(1,:));
longVer = strsplit(verComp, '.');
longVer = cellfun(@(x) str2double(regexp(x,'\d*','Match')), longVer(1,:));
shortVer_p = true;
longVer_p = false;
shortVer_s = length(shortVer);
longVer_s = length(longVer);

if shortVer_s > longVer_s
[longVer shortVer] = deal(shortVer,longVer);
[longVer_s shortVer_s] = deal(shortVer_s,longVer_s);
[longVer_p shortVer_p] = deal(shortVer_p,longVer_p);
end

shortVer = [shortVer zeros(1,longVer_s - shortVer_s)];
diff = shortVer - longVer;
match = diff ~= 0;

if ~match
res(i) = true;
else
pos = 1:longVer_s;
pos = pos(match);
val = diff(pos(1));
if val > 0
res(i) = shortVer_p;
elseif val < 0
res(i) = longVer_p;
end
end
end
end
Loading