Skip to content

Commit f599f82

Browse files
authored
Add relationship_type (#123)
* add one_on_one merge parameter * add vscode, pycharm, macos files to gitignore * one_on_one -> relationship_type
1 parent d6e73cb commit f599f82

File tree

6 files changed

+53
-14
lines changed

6 files changed

+53
-14
lines changed

.gitignore

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ cython_debug/
186186
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
187187
# and can be added to the global gitignore or merged into this file. For a more nuclear
188188
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
189-
# .idea/
189+
.idea/
190190

191191
# Abstra
192192
# Abstra is an AI-powered process automation framework.
@@ -199,7 +199,10 @@ cython_debug/
199199
# that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
200200
# and can be added to the global gitignore or merged into this file. However, if you prefer,
201201
# you could uncomment the following to ignore the entire vscode folder
202-
# .vscode/
202+
.vscode/
203+
204+
# MacOS
205+
.DS_Store
203206

204207
# Ruff stuff:
205208
.ruff_cache/

everyrow-mcp/src/everyrow_mcp/server.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,10 @@ class MergeInput(BaseModel):
352352
default=None,
353353
description='Optional. Control web search behavior: "auto" tries LLM merge first then conditionally searches, "no" skips web search entirely, "yes" forces web search on every row. Defaults to "auto" if not provided.',
354354
)
355+
relationship_type: Literal["many_to_one", "one_to_one"] | None = Field(
356+
default=None,
357+
description='Optional. Control merge relationship type: "many_to_one" (default) allows multiple left rows to match one right row, "one_to_one" enforces unique matching between left and right rows.',
358+
)
355359

356360
@field_validator("left_csv", "right_csv")
357361
@classmethod
@@ -394,6 +398,7 @@ async def everyrow_merge(params: MergeInput) -> str:
394398
merge_on_left=params.merge_on_left,
395399
merge_on_right=params.merge_on_right,
396400
use_web_search=params.use_web_search,
401+
relationship_type=params.relationship_type,
397402
)
398403

399404
output_file = resolve_output_path(params.output_path, params.left_csv, "merged")

src/everyrow/generated/models/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
from .merge_operation_left_input_type_1_item import MergeOperationLeftInputType1Item
2525
from .merge_operation_left_input_type_2 import MergeOperationLeftInputType2
2626
from .merge_operation_right_input_type_1_item import MergeOperationRightInputType1Item
27+
from .merge_operation_relationship_type_type_0 import MergeOperationRelationshipTypeType0
2728
from .merge_operation_right_input_type_2 import MergeOperationRightInputType2
2829
from .merge_operation_use_web_search_type_0 import MergeOperationUseWebSearchType0
2930
from .operation_response import OperationResponse
@@ -75,6 +76,7 @@
7576
"MergeOperationLeftInputType1Item",
7677
"MergeOperationLeftInputType2",
7778
"MergeOperationRightInputType1Item",
79+
"MergeOperationRelationshipTypeType0",
7880
"MergeOperationRightInputType2",
7981
"MergeOperationUseWebSearchType0",
8082
"OperationResponse",

src/everyrow/generated/models/merge_operation.py

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
from __future__ import annotations
22

33
from collections.abc import Mapping
4+
from everyrow.generated.types import Unset
45
from typing import TYPE_CHECKING, Any, TypeVar, cast
56
from uuid import UUID
67

78
from attrs import define as _attrs_define
89
from attrs import field as _attrs_field
910

11+
from ..models.merge_operation_relationship_type_type_0 import MergeOperationRelationshipTypeType0
1012
from ..models.merge_operation_use_web_search_type_0 import MergeOperationUseWebSearchType0
1113
from ..types import UNSET, Unset
1214

@@ -34,7 +36,9 @@ class MergeOperation:
3436
use_web_search (MergeOperationUseWebSearchType0 | None | Unset): Control web search behavior: 'auto' (default)
3537
tries LLM merge first then conditionally searches, 'no' skips web search entirely, 'yes' forces web search
3638
without initial LLM merge Default: MergeOperationUseWebSearchType0.AUTO.
37-
one_on_one (bool | None | Unset): Optional parameter for one-on-one merge behavior
39+
relationship_type (MergeOperationRelationshipTypeType0 | None | Unset): Control relationship type:
40+
'many_to_one' (default) allows multiple left rows to match one right row,
41+
'one_to_one' enforces unique matching between left and right rows.
3842
session_id (None | Unset | UUID): Session ID. If not provided, a new session is auto-created for this task.
3943
"""
4044

@@ -44,7 +48,7 @@ class MergeOperation:
4448
left_key: None | str | Unset = UNSET
4549
right_key: None | str | Unset = UNSET
4650
use_web_search: MergeOperationUseWebSearchType0 | None | Unset = MergeOperationUseWebSearchType0.AUTO
47-
one_on_one: bool | None | Unset = UNSET
51+
relationship_type: MergeOperationRelationshipTypeType0 | None | Unset = UNSET
4852
session_id: None | Unset | UUID = UNSET
4953
additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
5054

@@ -95,11 +99,13 @@ def to_dict(self) -> dict[str, Any]:
9599
else:
96100
use_web_search = self.use_web_search
97101

98-
one_on_one: bool | None | Unset
99-
if isinstance(self.one_on_one, Unset):
100-
one_on_one = UNSET
102+
relationship_type: None | str | Unset
103+
if isinstance(self.relationship_type, Unset):
104+
relationship_type = UNSET
105+
elif isinstance(self.relationship_type, MergeOperationRelationshipTypeType0):
106+
relationship_type = self.relationship_type.value
101107
else:
102-
one_on_one = self.one_on_one
108+
relationship_type = self.relationship_type
103109

104110
session_id: None | str | Unset
105111
if isinstance(self.session_id, Unset):
@@ -124,8 +130,8 @@ def to_dict(self) -> dict[str, Any]:
124130
field_dict["right_key"] = right_key
125131
if use_web_search is not UNSET:
126132
field_dict["use_web_search"] = use_web_search
127-
if one_on_one is not UNSET:
128-
field_dict["one_on_one"] = one_on_one
133+
if relationship_type is not UNSET:
134+
field_dict["relationship_type"] = relationship_type
129135
if session_id is not UNSET:
130136
field_dict["session_id"] = session_id
131137

@@ -241,14 +247,22 @@ def _parse_use_web_search(data: object) -> MergeOperationUseWebSearchType0 | Non
241247

242248
use_web_search = _parse_use_web_search(d.pop("use_web_search", UNSET))
243249

244-
def _parse_one_on_one(data: object) -> bool | None | Unset:
250+
def _parse_relationship_type(data: object) -> MergeOperationRelationshipTypeType0 | None | Unset:
245251
if data is None:
246252
return data
247253
if isinstance(data, Unset):
248254
return data
249-
return cast(bool | None | Unset, data)
255+
try:
256+
if not isinstance(data, str):
257+
raise TypeError()
258+
relationship_type_type_0 = MergeOperationRelationshipTypeType0(data)
259+
260+
return relationship_type_type_0
261+
except (TypeError, ValueError, AttributeError, KeyError):
262+
pass
263+
return cast(MergeOperationRelationshipTypeType0 | None | Unset, data)
250264

251-
one_on_one = _parse_one_on_one(d.pop("one_on_one", UNSET))
265+
relationship_type = _parse_relationship_type(d.pop("relationship_type", UNSET))
252266

253267
def _parse_session_id(data: object) -> None | Unset | UUID:
254268
if data is None:
@@ -274,7 +288,7 @@ def _parse_session_id(data: object) -> None | Unset | UUID:
274288
left_key=left_key,
275289
right_key=right_key,
276290
use_web_search=use_web_search,
277-
one_on_one=one_on_one,
291+
relationship_type=relationship_type,
278292
session_id=session_id,
279293
)
280294

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
from enum import Enum
2+
3+
4+
class MergeOperationRelationshipTypeType0(str, Enum):
5+
MANY_TO_ONE = "many_to_one"
6+
ONE_TO_ONE = "one_to_one"
7+
8+
def __str__(self) -> str:
9+
return str(self.value)

src/everyrow/ops.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -545,6 +545,7 @@ async def merge(
545545
merge_on_left: str | None = None,
546546
merge_on_right: str | None = None,
547547
use_web_search: Literal["auto", "yes", "no"] | None = None,
548+
relationship_type: Literal["many_to_one", "one_to_one"] | None = None,
548549
) -> MergeResult:
549550
"""Merge two tables using AI.
550551
@@ -556,6 +557,7 @@ async def merge(
556557
merge_on_left: Optional column name in left table to merge on
557558
merge_on_right: Optional column name in right table to merge on
558559
use_web_search: Optional. Control web search behavior: "auto" tries LLM merge first then conditionally searches, "no" skips web search entirely, "yes" forces web search on every row. Defaults to "auto" if not provided.
560+
relationship_type: Optional. Control merge relationship type: "many_to_one" (default) allows multiple left rows to match one right row, "one_to_one" enforces unique matching between left and right rows.
559561
560562
Returns:
561563
MergeResult containing the merged table and match breakdown by method (exact, fuzzy, llm, web)
@@ -578,6 +580,7 @@ async def merge(
578580
merge_on_left=merge_on_left,
579581
merge_on_right=merge_on_right,
580582
use_web_search=use_web_search,
583+
relationship_type=relationship_type,
581584
)
582585
return await merge_task.await_result()
583586
merge_task = await merge_async(
@@ -588,6 +591,7 @@ async def merge(
588591
merge_on_left=merge_on_left,
589592
merge_on_right=merge_on_right,
590593
use_web_search=use_web_search,
594+
relationship_type=relationship_type,
591595
)
592596
return await merge_task.await_result()
593597

@@ -600,6 +604,7 @@ async def merge_async(
600604
merge_on_left: str | None = None,
601605
merge_on_right: str | None = None,
602606
use_web_search: Literal["auto", "yes", "no"] | None = None,
607+
relationship_type: Literal["many_to_one", "one_to_one"] | None = None,
603608
) -> MergeTask:
604609
"""Submit a merge task asynchronously.
605610
@@ -616,6 +621,7 @@ async def merge_async(
616621
left_key=merge_on_left or UNSET,
617622
right_key=merge_on_right or UNSET,
618623
use_web_search=use_web_search or UNSET, # type: ignore
624+
relationship_type=relationship_type or UNSET, # type: ignore
619625
session_id=session.session_id,
620626
)
621627

0 commit comments

Comments
 (0)