github.com/mithrandie/csvq@v1.18.1/lib/query/table_path.go (about) 1 package query 2 3 import ( 4 "context" 5 "net/url" 6 "path/filepath" 7 "strings" 8 9 "github.com/mithrandie/csvq/lib/parser" 10 "github.com/mithrandie/csvq/lib/value" 11 ) 12 13 type DataObject struct { 14 *parser.BaseExpr 15 Raw string 16 } 17 18 func (o DataObject) String() string { 19 return o.Raw 20 } 21 22 type HttpObject struct { 23 *parser.BaseExpr 24 URL string 25 } 26 27 func (o HttpObject) String() string { 28 return o.URL 29 } 30 31 func ParseTableName(ctx context.Context, scope *ReferenceScope, table parser.Table) (parser.Identifier, error) { 32 if table.Alias != nil { 33 return table.Alias.(parser.Identifier), nil 34 } 35 36 name := parser.Identifier{ 37 BaseExpr: table.Object.GetBaseExpr(), 38 } 39 40 tableObject, err := NormalizeTableObject(ctx, scope, table.Object) 41 if err != nil { 42 return name, err 43 } 44 45 switch obj := tableObject.(type) { 46 case parser.Identifier: 47 name.Literal = FormatTableName(obj.Literal) 48 case parser.Stdin: 49 name.Literal = obj.String() 50 case parser.FormatSpecifiedFunction: 51 return ParseTableName(ctx, scope, parser.Table{Object: obj.Path}) 52 default: 53 // Do Nothing 54 } 55 return name, nil 56 } 57 58 func NormalizeTableObject(ctx context.Context, scope *ReferenceScope, tableObject parser.QueryExpression) (parser.QueryExpression, error) { 59 if tableFunction, ok := tableObject.(parser.TableFunction); ok { 60 p, err := ConvertTableFunction(ctx, scope, tableFunction) 61 if err != nil { 62 return nil, err 63 } 64 tableObject = p 65 } 66 67 if urlExpr, ok := tableObject.(parser.Url); ok { 68 p, err := ConvertUrlExpr(urlExpr) 69 if err != nil { 70 return nil, err 71 } 72 tableObject = p 73 } 74 75 return tableObject, nil 76 } 77 78 func ConvertTableFunction(ctx context.Context, scope *ReferenceScope, tableFunction parser.TableFunction) (parser.QueryExpression, error) { 79 name := strings.ToUpper(tableFunction.Name) 80 81 switch name { 82 case "FILE", "INLINE", "URL", "DATA": 83 if len(tableFunction.Args) != 1 { 84 return nil, NewFunctionArgumentLengthError(tableFunction, strings.ToUpper(tableFunction.Name), []int{1}) 85 } 86 default: 87 return nil, NewFunctionNotExistError(tableFunction, strings.ToUpper(tableFunction.Name)) 88 } 89 90 args := make([]value.Primary, len(tableFunction.Args)) 91 for i, v := range tableFunction.Args { 92 arg, err := Evaluate(ctx, scope, v) 93 if err != nil { 94 return nil, err 95 } 96 args[i] = arg 97 } 98 99 var expr parser.QueryExpression 100 101 switch name { 102 case "FILE", "INLINE": 103 p := value.ToString(args[0]) 104 if value.IsNull(p) { 105 return nil, NewFunctionInvalidArgumentError(tableFunction, strings.ToUpper(tableFunction.Name), "the first argument must be a string") 106 } 107 expr = parser.Identifier{BaseExpr: tableFunction.GetBaseExpr(), Literal: p.(*value.String).Raw()} 108 case "URL": 109 p := value.ToString(args[0]) 110 if value.IsNull(p) { 111 return nil, NewFunctionInvalidArgumentError(tableFunction, strings.ToUpper(tableFunction.Name), "the first argument must be a string") 112 } 113 expr = parser.Url{BaseExpr: tableFunction.GetBaseExpr(), Raw: p.(*value.String).Raw()} 114 case "DATA": 115 p := value.ToString(args[0]) 116 if value.IsNull(p) { 117 return nil, NewFunctionInvalidArgumentError(tableFunction, strings.ToUpper(tableFunction.Name), "the first argument must be a string") 118 } 119 expr = DataObject{BaseExpr: tableFunction.GetBaseExpr(), Raw: p.(*value.String).Raw()} 120 } 121 return expr, nil 122 } 123 124 func ConvertUrlExpr(urlExpr parser.Url) (parser.QueryExpression, error) { 125 u, e := url.Parse(urlExpr.Raw) 126 if e != nil { 127 return nil, NewInvalidUrlError(urlExpr) 128 } 129 130 switch u.Scheme { 131 case "http", "https": 132 return HttpObject{BaseExpr: urlExpr.GetBaseExpr(), URL: u.String()}, nil 133 case "file": 134 path := u.Path 135 var err error 136 137 if strings.HasPrefix(u.String(), "file://") { 138 if 0 < len(u.Host) { 139 return nil, NewInvalidUrlError(urlExpr) 140 } 141 if u.IsAbs() && 0 < len(path) && !filepath.IsAbs(path) { 142 path = path[1:] 143 } 144 } else { 145 path = u.String()[5:] 146 } 147 148 if len(path) < 1 { 149 path = "." 150 } 151 152 path, err = url.PathUnescape(path) 153 if err != nil { 154 return nil, NewInvalidUrlError(urlExpr) 155 } 156 157 return parser.Identifier{BaseExpr: urlExpr.GetBaseExpr(), Literal: path}, nil 158 } 159 return nil, NewUnsupportedUrlSchemeError(urlExpr, u.Scheme) 160 }