@@ -114,12 +114,12 @@ def build_foreign_key_parser():
114
114
return arrow + options + ref_table
115
115
116
116
117
- def build_attribute_parser ():
117
+ def build_attribute_parser (parse_metadata = False ):
118
118
quoted = pp .QuotedString ('"' ) ^ pp .QuotedString ("'" )
119
119
colon = pp .Literal (":" ).suppress ()
120
- attribute_name = pp .Word (pp . srange ( "[a-z]" ), pp . srange ( "[a-z0-9_]" )). setResultsName (
121
- "name"
122
- )
120
+ attribute_name = pp .Word (
121
+ pp . srange ( f"[a-z { '_' if parse_metadata else '' } ]" ), pp . srange ( "[a-z0-9_]" )
122
+ ). setResultsName ( "name" )
123
123
data_type = (
124
124
pp .Combine (pp .Word (pp .alphas ) + pp .SkipTo ("#" , ignore = quoted ))
125
125
^ pp .QuotedString ("<" , endQuoteChar = ">" , unquoteResults = False )
@@ -134,6 +134,7 @@ def build_attribute_parser():
134
134
foreign_key_parser_old = build_foreign_key_parser_old ()
135
135
foreign_key_parser = build_foreign_key_parser ()
136
136
attribute_parser = build_attribute_parser ()
137
+ metadata_attribute_parser = build_attribute_parser (parse_metadata = True )
137
138
138
139
139
140
def is_foreign_key (line ):
@@ -245,6 +246,7 @@ def prepare_declare(definition, context):
245
246
foreign_key_sql = []
246
247
index_sql = []
247
248
external_stores = []
249
+ metadata_attributes = ["_timestamp = CURRENT_TIMESTAMP : timestamp" ]
248
250
249
251
for line in definition :
250
252
if not line or line .startswith ("#" ): # ignore additional comments
@@ -272,6 +274,12 @@ def prepare_declare(definition, context):
272
274
if name not in attributes :
273
275
attributes .append (name )
274
276
attribute_sql .append (sql )
277
+ for line in metadata_attributes :
278
+ name , sql , store = compile_attribute (
279
+ line , in_key , foreign_key_sql , context , is_metadata = True
280
+ )
281
+ attributes .append (name )
282
+ attribute_sql .append (sql )
275
283
276
284
return (
277
285
table_comment ,
@@ -496,18 +504,22 @@ def substitute_special_type(match, category, foreign_key_sql, context):
496
504
assert False , "Unknown special type"
497
505
498
506
499
- def compile_attribute (line , in_key , foreign_key_sql , context ):
507
+ def compile_attribute (line , in_key , foreign_key_sql , context , is_metadata = False ):
500
508
"""
501
509
Convert attribute definition from DataJoint format to SQL
502
510
503
511
:param line: attribution line
504
512
:param in_key: set to True if attribute is in primary key set
505
513
:param foreign_key_sql: the list of foreign key declarations to add to
506
514
:param context: context in which to look up user-defined attribute type adapterss
515
+ :param is_metadata: flag to use an alternate parser for metadata attributes
507
516
:returns: (name, sql, is_external) -- attribute name and sql code for its declaration
508
517
"""
509
518
try :
510
- match = attribute_parser .parseString (line + "#" , parseAll = True )
519
+ if is_metadata :
520
+ match = metadata_attribute_parser .parseString (line + "#" , parseAll = True )
521
+ else :
522
+ match = attribute_parser .parseString (line + "#" , parseAll = True )
511
523
except pp .ParseException as err :
512
524
raise DataJointError (
513
525
"Declaration error in position {pos} in line:\n {line}\n {msg}" .format (
0 commit comments