Skip to content

Commit cb1c2ac

Browse files
Merge pull request #193 from guzman-raphael/uuid2
UUID
2 parents d6f6476 + 4efa46e commit cb1c2ac

File tree

8 files changed

+120
-8
lines changed

8 files changed

+120
-8
lines changed

+dj/+internal/Declare.m

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,12 @@
66
CONSTANT_LITERALS = {'CURRENT_TIMESTAMP'}
77
TYPE_PATTERN = struct( ...
88
'NUMERIC', '^((tiny|small|medium|big)?int|decimal|double|float)', ...
9-
'STRING', '^((var)?char|enum|date|(var)?binary|year|time|timestamp)', ...
10-
'INTERNAL_BLOB', '^(tiny|medium|long)?blob' ...
9+
'STRING', '^((var)?char|enum|date|(var)?year|time|timestamp)', ...
10+
'INTERNAL_BLOB', '^(tiny|medium|long)?blob', ...
11+
'UUID', 'uuid$' ...
1112
)
12-
SPECIAL_TYPES = {}
13+
UUID_DATA_TYPE = 'binary(16)'
14+
SPECIAL_TYPES = {'UUID'}
1315
end
1416

1517
methods(Static)
@@ -284,6 +286,9 @@ case regexp(line, ['^[a-z][a-z\d_]*\s*' ... % name
284286
% Substitute DataJoint type with sql type.
285287
% field: <struct> Modified in-place field attributes.
286288
% category: <string> DataJoint type match based on TYPE_PATTERN.
289+
if strcmpi(category, 'UUID')
290+
field.type = dj.internal.Declare.UUID_DATA_TYPE;
291+
end
287292
end
288293

289294
function sql = compileAttribute(field)

+dj/+internal/GeneralRelvar.m

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -866,6 +866,11 @@ case isa(cond, 'dj.internal.GeneralRelvar')
866866
assert(ischar(value), ...
867867
'Value for key.%s must be a string', field{1})
868868
value = sprintf('''%s''', escapeString(value));
869+
elseif attr.isUuid
870+
value = strrep(value, '-', '');
871+
assert(ischar(value) && length(value) == 32, ...
872+
'Value for key.%s must be a uuid HEX string.', field{1});
873+
value = sprintf('X''%s''', escapeString(value));
869874
else
870875
assert((isnumeric(value) || islogical(value)) && isscalar(value), ...
871876
'Value for key.%s must be a numeric scalar', field{1});
@@ -924,4 +929,17 @@ case isa(cond, 'dj.internal.GeneralRelvar')
924929
% Process in place fetched data.
925930
% data: <struct_array> Fetched records.
926931
% attr: <struct_array> Query fields details.
932+
for i = 1:length(attr)
933+
if attr(i).isUuid
934+
for j = 1:length(data)
935+
new_value = reshape(lower(dec2hex(data(j).(attr(i).name))).',1,[]);
936+
new_value = [new_value(1:8) '-' ...
937+
new_value(9:12) '-' ...
938+
new_value(13:16) '-' ...
939+
new_value(17:20) '-' ...
940+
new_value(21:end)];
941+
data(j).(attr(i).name) = new_value;
942+
end
943+
end
944+
end
927945
end

+dj/+internal/Header.m

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@
7979
attrs.isNumeric = false(length(attrs.isnullable), 1);
8080
attrs.isString = false(length(attrs.isnullable), 1);
8181
attrs.isBlob = false(length(attrs.isnullable), 1);
82+
attrs.isUuid = false(length(attrs.isnullable), 1);
8283
attrs.alias = cell(length(attrs.isnullable),1);
8384
attrs.sqlType = cell(length(attrs.isnullable),1);
8485
attrs.sqlComment = cell(length(attrs.isnullable),1);
@@ -91,7 +92,7 @@
9192
attrs.comment{i} = special{1}{2};
9293
end
9394
attrs.isnullable{i} = strcmpi(attrs.isnullable{i}, 'YES');
94-
attrs.iskey{i} = strcmpi(attrs.iskey{i}, 'PRI');
95+
attrs.iskey{i} = strcmpi(char(attrs.iskey{i}), 'PRI');
9596
attrs.isautoincrement(i) = ~isempty(regexpi(attrs.Extra{i}, ...
9697
'auto_increment', 'once'));
9798
attrs.isNumeric(i) = any(strcmpi( ...
@@ -100,13 +101,16 @@
100101
'STRING');
101102
attrs.isBlob(i) = strcmpi(dj.internal.Declare.matchType(attrs.type{i}), ...
102103
'INTERNAL_BLOB');
104+
attrs.isUuid(i) = strcmpi(dj.internal.Declare.matchType(attrs.type{i}), ...
105+
'UUID');
103106
% strip field lengths off integer types
104107
attrs.type{i} = regexprep(sprintf('%s',attrs.type{i}), ...
105108
'((tiny|small|medium|big)?int)\(\d+\)','$1');
106109
attrs.alias{i} = '';
107110
end
108111

109-
validFields = [attrs.isNumeric] | [attrs.isString] | [attrs.isBlob];
112+
validFields = [attrs.isNumeric] | [attrs.isString] | [attrs.isBlob] | ...
113+
[attrs.isUuid];
110114
if ~all(validFields)
111115
ix = find(~validFields, 1, 'first');
112116
error('unsupported field type "%s" in `%s`.`%s`', ...
@@ -165,6 +169,7 @@ function project(self, params)
165169
'isNumeric', true, ...
166170
'isString', false, ...
167171
'isBlob', false, ...
172+
'isUuid', false, ...
168173
'alias', toks{1}{1}, ...
169174
'sqlType', self.computedTypeString, ...
170175
'sqlComment', '' ...

+dj/Relvar.m

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,14 @@ function insert(self, tuples, command)
219219
placeholder = '"{S}"';
220220
value = char(value);
221221
end
222+
elseif header.attributes(attr_idx).isUuid
223+
placeholder = '"{B}"';
224+
value = strrep(value, '-', '');
225+
hexstring = value';
226+
reshapedString = reshape(hexstring,2,16);
227+
hexMtx = reshapedString.';
228+
decMtx = hex2dec(hexMtx);
229+
value = uint8(decMtx);
222230
elseif header.attributes(attr_idx).isBlob
223231
placeholder = '"{M}"';
224232
else

+tests/Main.m

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,6 @@
44
tests.TestERD & ...
55
tests.TestFetch & ...
66
tests.TestProjection & ...
7-
tests.TestTls
7+
tests.TestTls & ...
8+
tests.TestUuid
89
end

+tests/TestUuid.m

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
classdef TestUuid < tests.Prep
2+
% TestUuid tests uuid scenarios.
3+
methods (Test)
4+
function testInsertFetch(testCase)
5+
st = dbstack;
6+
disp(['---------------' st(1).name '---------------']);
7+
package = 'University';
8+
9+
c1 = dj.conn(...
10+
testCase.CONN_INFO.host,...
11+
testCase.CONN_INFO.user,...
12+
testCase.CONN_INFO.password,'',true);
13+
14+
dj.createSchema(package,[testCase.test_root '/test_schemas'], ...
15+
[testCase.PREFIX '_university']);
16+
17+
test_val1 = '1d751e2e-1e74-faf8-4ab4-85fde8ef72be';
18+
insert(University.Message, struct( ...
19+
'msg_id', test_val1, ...
20+
'body', 'Great campus!' ...
21+
));
22+
23+
test_val2 = '12321346-1312-4123-1234-312739283795';
24+
insert(University.Message, struct( ...
25+
'msg_id', test_val2, ...
26+
'body', 'Where can I find the gym?' ...
27+
));
28+
29+
q = University.Message;
30+
res = q.fetch('msg_id');
31+
value_check = res(1).msg_id;
32+
33+
testCase.verifyEqual(value_check, test_val2);
34+
end
35+
function testQuery(testCase)
36+
st = dbstack;
37+
disp(['---------------' st(1).name '---------------']);
38+
package = 'University';
39+
40+
c1 = dj.conn(...
41+
testCase.CONN_INFO.host,...
42+
testCase.CONN_INFO.user,...
43+
testCase.CONN_INFO.password,'',true);
44+
45+
test_val1 = '1d751e2e-1e74-faf8-4ab4-85fde8ef72be';
46+
test_val2 = '12321346-1312-4123-1234-312739283795';
47+
48+
q = University.Message & [struct('msg_id',test_val1),struct('msg_id',test_val2)];
49+
res = q.fetch('msg_id');
50+
value_check = res(2).msg_id;
51+
52+
testCase.verifyEqual(value_check, test_val1);
53+
end
54+
function testReverseEngineering(testCase)
55+
st = dbstack;
56+
disp(['---------------' st(1).name '---------------']);
57+
q = University.Message;
58+
raw_def = dj.internal.Declare.getDefinition(q);
59+
assembled_def = describe(q);
60+
raw_sql = dj.internal.Declare.declare(q, raw_def);
61+
assembled_sql = dj.internal.Declare.declare(q, assembled_def);
62+
testCase.verifyEqual(raw_sql, assembled_sql);
63+
end
64+
end
65+
end
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
%{
2+
# Message
3+
msg_id : uuid # test comment?
4+
---
5+
body : varchar(30)
6+
%}
7+
classdef Message < dj.Manual
8+
end

setupDJ.m

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@ function setupDJ(skipPathAddition, force)
2626
if ~isdir(mymdir)
2727
fprintf('mym missing. Downloading...\n')
2828
target = fullfile(base, 'mym.zip');
29-
mymURL = 'https://github.com/datajoint/mym/archive/master.zip';
29+
% mymURL = 'https://github.com/datajoint/mym/archive/master.zip';
30+
mymURL = 'https://github.com/datajoint/mym/archive/external-storage.zip';
3031
target = websave(target, mymURL);
3132
if isunix && ~ismac
3233
% on Linux Matlab unzip doesn't work properly so use system unzip
@@ -35,7 +36,8 @@ function setupDJ(skipPathAddition, force)
3536
unzip(target, base)
3637
end
3738
% rename extracted mym-master directory to mym
38-
movefile(fullfile(base, 'mym-master'), mymdir)
39+
% movefile(fullfile(base, 'mym-master'), mymdir)
40+
movefile(fullfile(base, 'mym-external-storage'), mymdir)
3941
delete(target)
4042
end
4143

0 commit comments

Comments
 (0)