9 |
9 |
10 def unset_attribute_storage(repo, etype, attr): |
10 def unset_attribute_storage(repo, etype, attr): |
11 repo.system_source.unset_storage(etype, attr) |
11 repo.system_source.unset_storage(etype, attr) |
12 |
12 |
13 class Storage(object): |
13 class Storage(object): |
14 """abstract storage""" |
14 """abstract storage |
15 def sqlgen_callback(self, generator, relation, linkedvar): |
15 |
16 """sql generator callback when some attribute with a custom storage is |
16 * If `source_callback` is true (by default), the callback will be run during |
17 accessed |
17 query result process of fetched attribute's valu and should have the |
|
18 following prototype:: |
|
19 |
|
20 callback(self, source, value) |
|
21 |
|
22 where `value` is the value actually stored in the backend. None values |
|
23 will be skipped (eg callback won't be called). |
|
24 |
|
25 * if `source_callback` is false, the callback will be run during sql |
|
26 generation when some attribute with a custom storage is accessed and |
|
27 should have the following prototype:: |
|
28 |
|
29 callback(self, generator, relation, linkedvar) |
|
30 |
|
31 where `generator` is the sql generator, `relation` the current rql syntax |
|
32 tree relation and linkedvar the principal syntax tree variable holding the |
|
33 attribute. |
|
34 """ |
|
35 is_source_callback = True |
|
36 |
|
37 def callback(self, *args): |
|
38 """see docstring for prototype, which vary according to is_source_callback |
18 """ |
39 """ |
19 raise NotImplementedError() |
40 raise NotImplementedError() |
20 |
41 |
21 def entity_added(self, entity, attr): |
42 def entity_added(self, entity, attr): |
22 """an entity using this storage for attr has been added""" |
43 """an entity using this storage for attr has been added""" |
36 class BytesFileSystemStorage(Storage): |
57 class BytesFileSystemStorage(Storage): |
37 """store Bytes attribute value on the file system""" |
58 """store Bytes attribute value on the file system""" |
38 def __init__(self, defaultdir): |
59 def __init__(self, defaultdir): |
39 self.default_directory = defaultdir |
60 self.default_directory = defaultdir |
40 |
61 |
41 def sqlgen_callback(self, generator, linkedvar, relation): |
62 def callback(self, source, value): |
42 """sql generator callback when some attribute with a custom storage is |
63 """sql generator callback when some attribute with a custom storage is |
43 accessed |
64 accessed |
44 """ |
65 """ |
45 linkedvar.accept(generator) |
66 fpath = source.binary_to_str(value) |
46 return '_fsopen(%s.cw_%s)' % ( |
67 try: |
47 linkedvar._q_sql.split('.', 1)[0], # table name |
68 return Binary(file(fpath).read()) |
48 relation.r_type) # attribute name |
69 except OSError, ex: |
|
70 source.critical("can't open %s: %s", value, ex) |
|
71 return None |
49 |
72 |
50 def entity_added(self, entity, attr): |
73 def entity_added(self, entity, attr): |
51 """an entity using this storage for attr has been added""" |
74 """an entity using this storage for attr has been added""" |
52 if not entity._cw.transaction_data.get('fs_importing'): |
75 if not entity._cw.transaction_data.get('fs_importing'): |
53 try: |
76 try: |