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
10 changes: 10 additions & 0 deletions +dj/+config/load.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
function load(fname)
switch nargin
case 0
dj.internal.Settings.load();
case 1
dj.internal.Settings.load(fname);
otherwise
error('Exceeded 1 input limit.');
end
end
3 changes: 3 additions & 0 deletions +dj/+config/restore.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
function out = restore()
out = dj.internal.Settings.restore();
end
10 changes: 10 additions & 0 deletions +dj/+config/save.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
function save(fname)
switch nargin
case 0
dj.internal.Settings.save();
case 1
dj.internal.Settings.save(fname);
otherwise
error('Exceeded 1 input limit.');
end
end
3 changes: 3 additions & 0 deletions +dj/+config/saveGlobal.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
function saveGlobal()
dj.internal.Settings.saveGlobal();
end
3 changes: 3 additions & 0 deletions +dj/+config/saveLocal.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
function saveLocal()
dj.internal.Settings.saveLocal();
end
12 changes: 6 additions & 6 deletions +dj/+internal/AutoPopulate.m
Original file line number Diff line number Diff line change
Expand Up @@ -111,12 +111,12 @@
%
% See also dj.internal.AutoPopulate/parpopulate

if ~dj.set('populateAncestors')
if ~dj.config('queryPopulate_ancestors')
rels = {self};
else
% get all ancestors to be populated before self
assert(nargout==0, ...
'parpopulate cannot return output when populateAncestors is true')
'parpopulate cannot return output when queryPopulate_ancestors is true')
rels = cellfun(@feval, self.ancestors, 'uni', false);
rels = rels(cellfun(@(x) isa(x,'dj.internal.AutoPopulate'), rels));
end
Expand Down Expand Up @@ -171,7 +171,7 @@ function parpopulate(self, varargin)
%
% See also dj.internal.AutoPopulate/populate

if ~dj.set('populateAncestors')
if ~dj.config('queryPopulate_ancestors')
rels = {self};
else
% get all ancestors to be populated before self
Expand Down Expand Up @@ -375,7 +375,7 @@ function cleanup(self, key)
success = false;
end
end
if ~success && dj.set('verbose')
if ~success && strcmpi(dj.config('loglevel'), 'DEBUG')
fprintf('** %s: skipping already reserved\n', self.className)
disp(key)
end
Expand Down Expand Up @@ -433,8 +433,8 @@ function createJobTable(self)
function populateSanityChecks(self)
% Performs sanity checks that are common to populate,
% parpopulate and batch_populate.
% To disable the sanity check: dj.set('populateCheck',false)
if dj.set('populateCheck')
% To disable the sanity check: dj.config('queryPopulate_check',false)
if dj.config('queryPopulate_check')
source = self.getKeySource;
abovePopRel = setdiff(self.primaryKey(1:min(end,length(source.primaryKey))), source.primaryKey);
if ~all(ismember(source.primaryKey, self.primaryKey))
Expand Down
2 changes: 1 addition & 1 deletion +dj/+internal/GeneralRelvar.m
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ function disp(self)
attrList{i} = hdr.names{i};
end
end
maxRows = dj.set('maxPreviewRows');
maxRows = dj.config('displayLimit');
preview = self.fetch(attrList{:}, sprintf('LIMIT %d', maxRows+1));
if ~isempty(preview)
hasMore = length(preview) > maxRows;
Expand Down
153 changes: 153 additions & 0 deletions +dj/+internal/Settings.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
classdef Settings < matlab.mixin.Copyable
properties (Constant)
LOCALFILE = './dj_local_conf.json'
GLOBALFILE = '~/.datajoint_config.json'
DEFAULTS = struct( ...
'databaseHost', 'localhost', ...
'databasePassword', [], ...
'databaseUser', [], ...
'databasePort', 3306, ...
'databaseUse_tls', [], ...
'databaseReconnect_transaction', false, ...
'connectionInit_function', [], ...
'loglevel', 'INFO', ...
'safemode', true, ...
'displayLimit', 12, ... how many rows to display when previewing a relation
'displayDiagram_hierarchy_radius', [2 1], ... levels up and down the hierachy to display in `erd schema.Table`
'displayDiagram_font_size', 12, ... font size to use in ERD labels
'queryPopulate_check', true, ...
'queryPopulate_ancestors', false, ...
'queryBigint_to_double', false, ...
'queryIgnore_extra_insert_fields', false ... when false, throws an error in `insert(self, tuple)` when tuple has extra fields.
)
end
properties
result
end
methods(Static)
function out = Settings(name, value)
current_state = stateAccess;
out.result = current_state;
if nargin == 1 || nargin == 2
assert(ischar(name), 'DataJoint:Config:InvalidType', ...
'Setting name must be a string');
token = regexp(['.', name], '(\W)(\w+)', 'tokens');
token = vertcat(token{:}).';
token(1,:) = strrep(strrep(token(1,:), '{', '{}'), '(', '()');
value_vector = str2double(token(2,:));
index = ~isnan(value_vector);
token(2, index) = num2cell(num2cell(value_vector(index)));
subscript = substruct(token{:});
if nargout
try
out.result = subsref(current_state, subscript);
catch ME
switch ME.identifier
case 'MATLAB:nonExistentField'
error('DataJoint:Config:InvalidKey', ...
'Setting `%s` does not exist', name);
otherwise
rethrow(ME);
end
end
else
out.result = [];
end
end
if nargin == 2
new_state = subsasgn(current_state, subscript, value);
stateAccess('set', new_state);
end
end
function out = restore()
out = stateAccess('restore');
end
function save(fname)
c = dj.internal.Settings;
dj.lib.saveJSONfile(c.result, fname);
end
function load(fname)
if ~nargin
fname = dj.internal.Settings.LOCALFILE;
end
raw = fileread(fname);
new_state = fixProps(jsondecode(raw), raw);
stateAccess('load', new_state);
end
function saveLocal()
dj.internal.Settings.save(dj.internal.Settings.LOCALFILE);
end
function saveGlobal()
dj.internal.Settings.save(dj.internal.Settings.GLOBALFILE);
end
end
end
function data = fixProps(data, raw)
newFields = fieldnames(data);
for i=1:length(newFields)
for j=1:length(data.(newFields{i}))
if isstruct(data.(newFields{i})(j))
if exist('res','var')
res(end + 1) = fixProps(data.(newFields{i})(j), raw);
else
res = fixProps(data.(newFields{i})(j), raw);
end
if j == length(data.(newFields{i}))
data.(newFields{i}) = res;
clear res;
end
end
end
newFields{i} = regexprep(regexp(raw, ...
regexprep(newFields{i},'_','.'), 'match', 'once'), ...
'\.[a-zA-Z0-9]','${upper($0(2))}');
end
data = cell2struct(struct2cell(data), newFields);
end
function out = stateAccess(operation, new)
function envVarUpdate()
% optional environment variables specifying the connection.
if getenv('DJ_HOST')
STATE.databaseHost = getenv('DJ_HOST');
end
if getenv('DJ_USER')
STATE.databaseUser = getenv('DJ_USER');
end
if getenv('DJ_PASS')
STATE.databasePassword = getenv('DJ_PASS');
end
if getenv('DJ_INIT')
STATE.connectionInit_function = getenv('DJ_INIT');
end
end
switch nargin
case 0
operation = '';
case 1
case 2
otherwise
error('Exceeded 2 input limit.')
end
persistent STATE
if (isempty(STATE) && ~strcmpi(operation, 'load')) || strcmpi(operation, 'restore')
% default settings
STATE = orderfields(dj.internal.Settings.DEFAULTS);
if exist(dj.internal.Settings.LOCALFILE, 'file') == 2
dj.internal.Settings.load(dj.internal.Settings.LOCALFILE);
elseif exist(dj.internal.Settings.GLOBALFILE, 'file') == 2
dj.internal.Settings.load(dj.internal.Settings.GLOBALFILE);
end
envVarUpdate();
end
% return STATE prior to change
out = STATE;
if any(strcmpi(operation, {'set', 'load'}))
% 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));
if strcmpi(operation, 'load')
envVarUpdate();
end
end
end
8 changes: 4 additions & 4 deletions +dj/+internal/Table.m
Original file line number Diff line number Diff line change
Expand Up @@ -191,11 +191,11 @@ function erd(self, up, down)

self.create
if nargin<=2
down = dj.set('tableErdRadius');
down = dj.config('displayDiagram_hierarchy_radius');
down = down(2);
end
if nargin<=1
up = dj.set('tableErdRadius');
up = dj.config('displayDiagram_hierarchy_radius');
up = up(1);
end

Expand Down Expand Up @@ -465,7 +465,7 @@ function syncDef(self)
if isempty(path)
fprintf('File %s.m is not found\n', self.className);
else
if ~dj.set('suppressPrompt') ...
if dj.config('safemode') ...
&& ~strcmpi('yes', dj.internal.ask(sprintf('Update the table definition and class definition in %s?',path)))
disp 'No? Table definition left untouched.'
else
Expand Down Expand Up @@ -549,7 +549,7 @@ function drop(self)
end

% if any table has data, give option to cancel
doPrompt = doPrompt && ~dj.set('suppressPrompt'); % suppress prompt
doPrompt = doPrompt && dj.config('safemode'); % suppress prompt
if doPrompt && ~strcmpi('yes', dj.internal.ask('Proceed to drop?'))
disp 'User cancelled table drop'
else
Expand Down
83 changes: 83 additions & 0 deletions +dj/+lib/saveJSONfile.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
function saveJSONfile(data, jsonFileName)
% Modified from FileExchange entry:
% https://www.mathworks.com/matlabcentral/fileexchange/...
% 50965-structure-to-json?focused=3876199&tab=function
% saves the values in the structure 'data' to a file in JSON indented format.
%
% Example:
% data.name = 'chair';
% data.color = 'pink';
% data.metrics.height = 0.3;
% data.metrics.width = 1.3;
% saveJSONfile(data, 'out.json');
%
% Output 'out.json':
% {
% "name" : "chair",
% "color" : "pink",
% "metrics" : {
% "height" : 0.3,
% "width" : 1.3
% }
% }
%
fid = fopen(jsonFileName,'w');
writeElement(fid, data,'');
fprintf(fid,'\n');
fclose(fid);
end
function writeElement(fid, data,tabs)
namesOfFields = fieldnames(data);
tabs = sprintf('%s\t',tabs);
fprintf(fid,'{\n%s',tabs);
key = true;
for i = 1:length(namesOfFields) - 1
currentField = namesOfFields{i};
currentElementValue = data.(currentField);
writeSingleElement(fid, currentField,currentElementValue,tabs, key);
fprintf(fid,',\n%s',tabs);
end
currentField = namesOfFields{end};
currentElementValue = data.(currentField);
writeSingleElement(fid, currentField,currentElementValue,tabs, key);
fprintf(fid,'\n%s}',tabs(1:end-1));
end
function writeSingleElement(fid, currentField,currentElementValue,tabs, key)
% if this is an array and not a string then iterate on every
% element, if this is a single element write it
currentField = regexprep(currentField,'[a-z0-9][A-Z]','${$0(1)}.${lower($0(2))}');
if key
fprintf(fid,'"%s" : ' , currentField);
end
if length(currentElementValue) > 1 && ~ischar(currentElementValue)
fprintf(fid,'[\n%s\t',tabs);
for m = 1:length(currentElementValue)-1
if isstruct(currentElementValue(m))
writeElement(fid, currentElementValue(m),tabs);
else
writeSingleElement(fid, '',currentElementValue(m),tabs, false)
end
fprintf(fid,',\n%s\t',tabs);
end
if isstruct(currentElementValue(end))
writeElement(fid, currentElementValue(end),tabs);
else
writeSingleElement(fid, '',currentElementValue(end),tabs, false)
end
fprintf(fid,'\n%s]',tabs);
elseif isstruct(currentElementValue)
writeElement(fid, currentElementValue,tabs);
elseif isempty(currentElementValue)
fprintf(fid,'null');
elseif isnumeric(currentElementValue)
fprintf(fid,'%g' ,currentElementValue);
elseif islogical(currentElementValue)
if currentElementValue
fprintf(fid,'true');
else
fprintf(fid,'false');
end
else %ischar or something else ...
fprintf(fid,'"%s"',currentElementValue);
end
end
4 changes: 2 additions & 2 deletions +dj/Connection.m
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ function reload(self)
ret = ~isempty(self.connId) && 0==mym(self.connId, 'status');

if ~ret && self.inTransaction
if dj.set('reconnectTimedoutTransaction')
if dj.config('databaseReconnect_transaction')
warning 'Reconnected after server disconnected during a transaction'
else
error 'Server disconnected during a transaction'
Expand All @@ -170,7 +170,7 @@ function reload(self)
end
end
v = varargin;
if dj.set('bigint_to_double')
if dj.config('queryBigint_to_double')
v{end+1} = 'bigint_to_double';
end
if nargout>0
Expand Down
2 changes: 1 addition & 1 deletion +dj/ERD.m
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ function draw(self)
for i=1:self.graph.numnodes
if tiers(i)<7 % ignore jobs, logs, etc.
isPart = tiers(i)==6;
fs = dj.set('erdFontSize')*(1 - 0.3*isPart);
fs = dj.config('displayDiagram_font_size')*(1 - 0.3*isPart);
fc = isPart*0.3*[1 1 1];
name = self.conn.tableToClass(self.graph.Nodes.Name{i});
text(h.XData(i)+0.1, h.YData(i), name, ...
Expand Down
Loading