Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
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
2 changes: 1 addition & 1 deletion +dj/+internal/GeneralRelvar.m
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,7 @@ function clip(self)
% if renamed, use the renamed attribute
name = regexp(specs{iArg}, '(\w+)\s*$', 'tokens');
sel = cellfun(@(x) strcmp(x, name{1}{1}), {self.header.attributes.name});
if self.tableHeader.attributes(sel).isNumeric
if self.header.attributes(sel).isNumeric
varargout{iArg} = [s.(name{1}{1})]';
else
varargout{iArg} = {s.(name{1}{1})}';
Expand Down
9 changes: 7 additions & 2 deletions +dj/+internal/Settings.m
Original file line number Diff line number Diff line change
Expand Up @@ -148,12 +148,17 @@ function envVarUpdate()
out = STATE;
if any(strcmpi(operation, {'set', 'load'}))
if isempty(STATE)
STATE = new;
STATE = rmfield(dj.internal.Settings.DEFAULTS, intersect(fieldnames( ...
dj.internal.Settings.DEFAULTS), fieldnames(new)));
names = [fieldnames(STATE); fieldnames(new)];
STATE = orderfields(...
cell2struct([struct2cell(STATE); struct2cell(new)], names, 1));
else
% merge with existing STATE
STATE = rmfield(STATE, intersect(fieldnames(STATE), fieldnames(new)));
names = [fieldnames(STATE); fieldnames(new)];
STATE = orderfields(cell2struct([struct2cell(STATE); struct2cell(new)], names, 1));
STATE = orderfields(...
cell2struct([struct2cell(STATE); struct2cell(new)], names, 1));
end
if strcmpi(operation, 'load')
envVarUpdate();
Expand Down
26 changes: 23 additions & 3 deletions +dj/Relvar.m
Original file line number Diff line number Diff line change
Expand Up @@ -87,9 +87,29 @@ function cleanup(self)
self.schema.conn.tableToClass(child),list)), rels(i).children)
% and restrict them by it or its restrictions
if restrictByMe(i)
% TODO: handle renamed attributes self.conn.foreignKeys( ...
% fullTableName).aliased
rels(ix).restrict(pro(rels(i)))
% Extract foreign key indices for table that match target parent
fk_index = arrayfun(...
@(x) strcmp(x.from, rels(ix).fullTableName), ...
self.schema.conn.foreignKeys, 'uni', true);
fks = self.schema.conn.foreignKeys(fk_index);
if ~fks.aliased
% If matched foreign keys are not aliased, no renaming
% necessary. Restrict table based on normal projection.
rels(ix).restrict(proj(rels(i)));
else
% Determine which foreign keys have been renamed
alias_index = cellfun(...
@(ref_attr, attr) ~strcmp(ref_attr, attr), ...
fks.ref_attrs, fks.attrs, 'uni', true);
% Create rename arguments for projection
aliased_attrs = cellfun(...
@(ref_attr, attr) sprintf('%s->%s', ref_attr, attr), ...
fks.ref_attrs(alias_index), fks.attrs(alias_index), ...
'uni', false);
% Restrict table based on projection with rename arguments on
% foreign keys.
rels(ix).restrict(proj(rels(i), aliased_attrs{:}));
end
else
rels(ix).restrict(rels(i).restrictions{:});
end
Expand Down
2 changes: 1 addition & 1 deletion +dj/struct.m
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@
s = dj.struct.proj(s, varargin{:});
end

function s = proj(s,varargin)
function s = proj(s, varargin)
% DJ.STRUCT.PROJ - the relational projection operator
% of structure array onto the specified fields.
% The result may contain duplicate tuples.
Expand Down
2 changes: 1 addition & 1 deletion +dj/version.m
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
function varargout = version
% report DataJoint version

v = struct('major',3,'minor',4,'bugfix',3);
v = struct('major', 3, 'minor', 4, 'bugfix', 3);

if nargout
varargout{1}=v;
Expand Down
6 changes: 5 additions & 1 deletion docs-parts/intro/Releases_lang1.rst
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
3.4.3 -- May 28, 2021
---------------------
--------------------------
* Bugfix: `dj.config` omits default values when loading new config immediately after MATLAB boot (#359) PR #369
* Bugfix: Regression error when using fetchn with a join (#361) PR #369
* Bugfix: Cascading delete not functioning properly when using renamed foreign keys (#362) PR #369
* Update NGINX reverse-proxy image use PR #369
* Bugfix: Add support to curly brackets in comments (#365) PR #373

3.4.2 -- March 16, 2021
Expand Down
1 change: 1 addition & 0 deletions tests/Main.m
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
classdef Main < ...
TestConfig & ...
TestConnection & ...
TestDelete & ...
TestDeclaration & ...
TestERD & ...
TestExternalFile & ...
Expand Down
16 changes: 14 additions & 2 deletions tests/TestConfig.m
Original file line number Diff line number Diff line change
Expand Up @@ -200,8 +200,20 @@ function TestConfig_testLoad(testCase)
% test load on launch MATLAB
clear functions;
dj.config.load(sprintf('%s/test_schemas/config_lite.json', pkg_path));
% cleanup
dj.config.restore;
try
port = dj.config('databasePort');
testCase.verifyEqual(port, 3306);
catch ME
switch ME.identifier
case 'DataJoint:Config:InvalidKey'
% cleanup
dj.config.restore;
rethrow(ME);
otherwise
% cleanup
dj.config.restore;
end
end
end
function TestConfig_testEnv(testCase)
st = dbstack;
Expand Down
40 changes: 40 additions & 0 deletions tests/TestDelete.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
classdef TestDelete < Prep
% TestDelete tests delete operations.
methods (Test)
function TestDelete_testRenamedDelete(testCase)
st = dbstack;
disp(['---------------' st(1).name '---------------']);
% https://github.com/datajoint/datajoint-matlab/issues/362
dj.config('safemode', false);
package = 'Company';

c1 = dj.conn(...
testCase.CONN_INFO.host,...
testCase.CONN_INFO.user,...
testCase.CONN_INFO.password,'',true);

dj.createSchema(package,[testCase.test_root '/test_schemas'], ...
[testCase.PREFIX '_company']);

inserti(Company.Employee, {'raphael', 2019; 'shan', 2018; 'chris', 2018; ...
'thinh', 2019});
inserti(Company.Duty, {'schedule1', 'shan', 2018; 'schedule2', 'raphael', 2019});
inserti(Company.Machine, {'shan', 2018, 'abc1023'; 'raphael', 2019, 'xyz9876'});
testCase.verifyEqual(length(fetch(Company.Employee)), 4);
testCase.verifyEqual(length(fetch(Company.Duty)), 2);
testCase.verifyEqual(length(fetch(Company.Machine)), 2);

del(Company.Employee & 'employee_id="shan"');

testCase.verifyEqual(length(fetch(Company.Employee)), 3);
testCase.verifyEqual(...
length(fetch(Company.Employee & struct('employee_id', 'shan'))), 0);
testCase.verifyEqual(length(fetch(Company.Duty)), 1);
testCase.verifyEqual(...
length(fetch(Company.Duty & struct('monday_on_call', 'shan'))), 0);
testCase.verifyEqual(length(fetch(Company.Machine)), 1);
testCase.verifyEqual(...
length(fetch(Company.Machine & struct('employee_id', 'shan'))), 0);
end
end
end
2 changes: 1 addition & 1 deletion tests/TestExternalFile.m
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ function TestExternalFile_checks(test_instance, store, cache)
'dimension_id', 4, ...
'dimension', test_val1 ...
));
% check that external tables are loaded on new schema objs if they already exists
% check that external tables are loaded on new schema objs if they already exist
delete([test_instance.test_root '/test_schemas' '/+' package '/getSchema.m']);
dj.createSchema(package,[test_instance.test_root '/test_schemas'], ...
[test_instance.PREFIX '_external']);
Expand Down
18 changes: 18 additions & 0 deletions tests/TestFetch.m
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,24 @@ function TestFetch_testFetchn(testCase)
testCase.verifyEqual(q.fetchn('number'), []);
testCase.verifyEqual(q.fetchn('blob'), {});
end
function TestFetch_testFetchnJoin(testCase)
st = dbstack;
disp(['---------------' st(1).name '---------------']);
% https://github.com/datajoint/datajoint-matlab/issues/361
% https://github.com/datajoint/datajoint-matlab/issues/364
package = 'Lab';

c1 = dj.conn(...
testCase.CONN_INFO.host,...
testCase.CONN_INFO.user,...
testCase.CONN_INFO.password,'',true);

dj.createSchema(package,[testCase.test_root '/test_schemas'], ...
[testCase.PREFIX '_lab']);

q = Lab.Session * Lab.Rig & 'rig_model="nonexistent"';
testCase.verifyEqual(q.fetchn('rig_note'), {});
end
function TestFetch_testDescribe(testCase)
st = dbstack;
disp(['---------------' st(1).name '---------------']);
Expand Down
7 changes: 7 additions & 0 deletions tests/test_schemas/+Company/Duty.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
%{
schedule: varchar(32)
---
(monday_on_call) -> Company.Employee(employee_id)
%}
classdef Duty < dj.Manual
end
7 changes: 7 additions & 0 deletions tests/test_schemas/+Company/Employee.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
%{
#
employee_id : varchar(12) #
employment_year : int #
%}
classdef Employee < dj.Manual
end
6 changes: 6 additions & 0 deletions tests/test_schemas/+Company/Machine.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
%{
-> Company.Employee
machine_id: varchar(10)
%}
classdef Machine < dj.Manual
end