Skip to content

Commit df2b245

Browse files
authored
Merge pull request #2 from guzman-raphael/A-Baji_multi-table-insert
Allow multiple submissions, maps are now individually optional.
2 parents b24f995 + 2c2a8a4 commit df2b245

File tree

1 file changed

+94
-100
lines changed

1 file changed

+94
-100
lines changed

pharus/component_interface.py

Lines changed: 94 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ def __init__(
146146
password=jwt_payload["password"],
147147
reset=True,
148148
)
149-
self.fields_map = component_config["map"] if "map" in component_config else None
149+
self.fields_map = component_config.get("map")
150150
self.tables = [
151151
getattr(
152152
dj.VirtualModule(
@@ -158,115 +158,109 @@ def __init__(
158158
)
159159
for s, t in (_.split(".") for _ in component_config["tables"])
160160
]
161-
162-
def _get_datatype_map(self):
163-
attributes = reduce(
164-
lambda a0, a1: {**a0, **a1}, (t.heading.attributes for t in self.tables)
161+
self.parents = set(
162+
[
163+
p
164+
for t in self.tables
165+
for p in t.parents(as_objects=True)
166+
if p.full_table_name not in (t.full_table_name for t in self.tables)
167+
]
165168
)
166-
datatype_map = {k: v.type for k, v in attributes.items()}
167-
return datatype_map
168169

169170
def dj_query_route(self):
170171
with self.connection.transaction:
171-
if self.fields_map:
172-
field_name_map = {}
173-
for field in self.fields_map:
174-
if field["type"] != "table":
175-
field_name_map[
176-
field["input"] if "input" in field else field["destination"]
177-
] = field["destination"]
178-
else:
179-
for submap in field["map"]:
180-
field_name_map[
181-
submap["input"]
182-
if "input" in submap
183-
else submap["destination"]
184-
] = submap["destination"]
185-
self.payload = {field_name_map[k]: v for k, v in self.payload.items()}
172+
destination_lookup = reduce(
173+
lambda m0, m1: dict(
174+
m0,
175+
**(
176+
{
177+
m_t["input"]
178+
if "input" in m_t
179+
else m_t["destination"]: m_t["destination"]
180+
for m_t in m1["map"]
181+
}
182+
if m1["type"] == "table"
183+
else {
184+
m1["input"]
185+
if "input" in m1
186+
else m1["destination"]: m1["destination"]
187+
}
188+
),
189+
),
190+
self.fields_map or [],
191+
{},
192+
)
186193
for t in self.tables:
187-
t.insert1(
188-
{k: v for k, v in self.payload.items() if k in t.heading.attributes}
194+
t.insert(
195+
[
196+
{
197+
a: v
198+
for k, v in r.items()
199+
if (a := destination_lookup.get(k, k))
200+
in t.heading.attributes
201+
}
202+
for r in self.payload["submissions"]
203+
]
189204
)
190205
return "Insert successful"
191206

192207
def fields_route(self):
193-
fields = []
194-
if self.fields_map:
195-
datatype_map = self._get_datatype_map()
196-
for field in self.fields_map:
197-
field_type = field["type"]
198-
field_name = (
199-
field["input"] if "input" in field else field["destination"]
200-
)
201-
if field_type == "attribute":
202-
field_datatype = datatype_map[field["destination"]]
203-
fields.append(
204-
dict(type=field_type, datatype=field_datatype, name=field_name)
205-
)
206-
elif field_type == "table":
207-
s, t = field["destination"].split(".")
208-
if "map" in field:
209-
proj_map = {
210-
attr["input"]
211-
if "input" in attr
212-
else attr["destination"]: attr["destination"]
213-
for attr in field["map"]
214-
}
215-
records = (
216-
getattr(
217-
dj.VirtualModule(
218-
s,
219-
s,
220-
connection=self.connection,
221-
),
222-
t,
223-
)
224-
.proj(**proj_map)
225-
.fetch("KEY")
226-
)
227-
else:
228-
records = getattr(
229-
dj.VirtualModule(
230-
s,
231-
s,
232-
connection=self.connection,
233-
),
234-
t,
235-
).fetch("KEY")
236-
fields.append(
237-
dict(type=field_type, values=records, name=field_name)
238-
)
239-
else:
240-
for t in self.tables:
241-
for v in t.heading.attributes.values():
242-
is_fk = False
243-
for p in t.parents(as_objects=True):
244-
if v.name in p.primary_key:
245-
is_fk = True
246-
field_name = (
247-
f"{p.database}.{dj.utils.to_camel_case(p.table_name)}"
248-
)
249-
if field_name not in [
250-
field["name"] for field in fields
251-
] and field_name not in [
252-
f"{t.database}.{t.__name__}" for t in self.tables
253-
]:
254-
fields.append(
255-
dict(
256-
type="table",
257-
values=p.fetch("KEY"),
258-
name=field_name,
208+
parent_attributes = set(sum([p.primary_key for p in self.parents], []))
209+
source_fields = {
210+
**{
211+
(p_name := f"{p.database}.{dj.utils.to_camel_case(p.table_name)}"): {
212+
"values": p.fetch("KEY", as_dict=True),
213+
"type": "table",
214+
"name": p_name,
215+
}
216+
for p in self.parents
217+
},
218+
**{
219+
a: {"datatype": v.type, "type": "attribute", "name": v.name}
220+
for t in self.tables
221+
for a, v in t.heading.attributes.items()
222+
if a not in parent_attributes
223+
},
224+
}
225+
226+
if not self.fields_map:
227+
return dict(fields=source_fields)
228+
return dict(
229+
fields=[
230+
dict(
231+
(field := source_fields.pop(m["destination"])),
232+
name=m["input" if "input" in m else "destination"],
233+
**(
234+
{
235+
"values": field["values"]
236+
if "map" not in m
237+
else [
238+
{
239+
input_lookup[k]: v
240+
for k, v in r.items()
241+
if k
242+
in (
243+
input_lookup := {
244+
table_m["destination"]: table_m[
245+
"input"
246+
if "input" in table_m
247+
else "destination"
248+
]
249+
for table_m in m["map"]
250+
}
259251
)
260-
)
261-
if not is_fk:
262-
fields.append(
263-
dict(
264-
type="attribute",
265-
datatype=v.type,
266-
name=v.name,
267-
)
268-
)
269-
return dict(fields=fields)
252+
}
253+
for r in field["values"]
254+
]
255+
}
256+
if m["type"] == "table"
257+
else {}
258+
),
259+
)
260+
for m in self.fields_map
261+
]
262+
+ list(source_fields.values())
263+
)
270264

271265

272266
class TableComponent(FetchComponent):

0 commit comments

Comments
 (0)