-
Notifications
You must be signed in to change notification settings - Fork 46
Add JSONL input support for tuple import #527
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| {"user": "user:anne", "relation": "owner", "object": "folder:product"} | ||
| {"user": "folder:product", "relation": "parent", "object": "folder:product-2021"} | ||
| {"user": "user:beth", "relation": "viewer", "object": "folder:product-2021"} | ||
| {"user": "folder:product", "relation": "parent", "object": "folder:product-2021", "condition": {"name": "inOfficeIP", "context": {"ip_addr": "10.0.0.1"}}} |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -12,7 +12,7 @@ | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "github.com/openfga/cli/internal/clierrors" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| func ReadTupleFile(fileName string) ([]client.ClientTupleKey, error) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| data, err := os.ReadFile(fileName) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if err != nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return nil, fmt.Errorf("failed to read file %q: %w", fileName, err) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -20,12 +20,26 @@ | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| var tuples []client.ClientTupleKey | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| switch path.Ext(fileName) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| case ".json", ".yaml", ".yml": | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| err = yaml.Unmarshal(data, &tuples) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if err == nil && len(tuples) == 0 { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| err = clierrors.EmptyTuplesFileError(strings.TrimPrefix(path.Ext(fileName), ".")) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ext := path.Ext(fileName) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| switch ext { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| case ".json": | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| err = yaml.Unmarshal(data, &tuples) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if err != nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| err = parseTuplesFromJSONL(data, &tuples, "json") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if err == nil && len(tuples) == 0 { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| err = clierrors.EmptyTuplesFileError("json") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| case ".jsonl": | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| err = parseTuplesFromJSONL(data, &tuples, "jsonl") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if err == nil && len(tuples) == 0 { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| err = clierrors.EmptyTuplesFileError("jsonl") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| case ".yaml", ".yml": | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| err = yaml.Unmarshal(data, &tuples) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if err == nil && len(tuples) == 0 { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| err = clierrors.EmptyTuplesFileError(strings.TrimPrefix(ext, ".")) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
23
to
+42
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fix formatting and improve error handling logic. The implementation correctly handles both JSON array and JSONL formats for
Apply this diff to fix the formatting and improve the logic: - ext := path.Ext(fileName)
- switch ext {
- case ".json":
- err = yaml.Unmarshal(data, &tuples)
- if err != nil {
- err = parseTuplesFromJSONL(data, &tuples, "json")
- }
- if err == nil && len(tuples) == 0 {
- err = clierrors.EmptyTuplesFileError("json")
- }
- case ".jsonl":
- err = parseTuplesFromJSONL(data, &tuples, "jsonl")
- if err == nil && len(tuples) == 0 {
- err = clierrors.EmptyTuplesFileError("jsonl")
- }
- case ".yaml", ".yml":
- err = yaml.Unmarshal(data, &tuples)
- if err == nil && len(tuples) == 0 {
- err = clierrors.EmptyTuplesFileError(strings.TrimPrefix(ext, "."))
- }
+ ext := path.Ext(fileName)
+ switch ext {
+ case ".json":
+ err = yaml.Unmarshal(data, &tuples)
+ if err != nil {
+ err = parseTuplesFromJSONL(data, &tuples, "json")
+ }
+ if err == nil && len(tuples) == 0 {
+ err = clierrors.EmptyTuplesFileError("json")
+ }
+ case ".jsonl":
+ err = parseTuplesFromJSONL(data, &tuples, "jsonl")
+ if err == nil && len(tuples) == 0 {
+ err = clierrors.EmptyTuplesFileError("jsonl")
+ }
+ case ".yaml", ".yml":
+ err = yaml.Unmarshal(data, &tuples)
+ if err == nil && len(tuples) == 0 {
+ err = clierrors.EmptyTuplesFileError(strings.TrimPrefix(ext, "."))
+ }📝 Committable suggestion
Suggested change
🧰 Tools🪛 GitHub Check: Lints[failure] 30-30: [failure] 23-23: 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| case ".csv": | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| err = parseTuplesFromCSV(data, &tuples) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| default: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -38,3 +52,26 @@ | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return tuples, nil | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| func parseTuplesFromJSONL(data []byte, tuples *[]client.ClientTupleKey, format string) error { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| lines := strings.Split(strings.TrimSpace(string(data)), "\n") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for index, line := range lines { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| trimmed := strings.TrimSpace(line) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if trimmed == "" { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| continue | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| var tuple client.ClientTupleKey | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if err := yaml.Unmarshal([]byte(trimmed), &tuple); err != nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return fmt.Errorf("failed to parse tuple on line %d: %w", index+1, err) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| *tuples = append(*tuples, tuple) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if len(*tuples) == 0 { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return clierrors.EmptyTuplesFileError(format) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return nil | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
56
to
77
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Remove duplicate empty check and fix error wrapping. The Apply this diff to fix the issues: func parseTuplesFromJSONL(data []byte, tuples *[]client.ClientTupleKey, format string) error {
lines := strings.Split(strings.TrimSpace(string(data)), "\n")
for index, line := range lines {
trimmed := strings.TrimSpace(line)
if trimmed == "" {
continue
}
var tuple client.ClientTupleKey
if err := yaml.Unmarshal([]byte(trimmed), &tuple); err != nil {
return fmt.Errorf("failed to parse tuple on line %d: %w", index+1, err)
}
*tuples = append(*tuples, tuple)
}
- if len(*tuples) == 0 {
- return clierrors.EmptyTuplesFileError(format)
- }
-
return nil
}The empty file check is already handled by the caller, making this redundant. Also, consider using
🧰 Tools🪛 GitHub Check: Lints[failure] 73-73: 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Fix formatting in the test case.
The test case correctly verifies JSONL parsing functionality and includes a tuple with conditions to ensure comprehensive coverage. However, the formatting needs to be corrected.
Apply this diff to fix the formatting:
📝 Committable suggestion
🧰 Tools
🪛 GitHub Check: Lints
[failure] 152-152:
File is not properly formatted (gofmt)
🤖 Prompt for AI Agents