diff --git a/example.hav b/example.hav index 9ad52b5..b7e9b57 100644 --- a/example.hav +++ b/example.hav @@ -1,6 +1,7 @@ entity user { name Person.Name email Internet.Email + image Person.Image.Name } entity product { diff --git a/handler.go b/handler.go index 84f5aeb..5640512 100644 --- a/handler.go +++ b/handler.go @@ -38,6 +38,15 @@ func HandleBase(w http.ResponseWriter, r *http.Request, s *Source, opt *ServeOpt return } + if strings.HasPrefix(path, "static/") && opt.tmp { + mimeType := "application/octet-stream" + + w.Header().Set("Content-Type", mimeType) + + http.ServeFile(w, r, "/tmp/"+strings.TrimPrefix(path, "static/")) + return + } + if response == nil { w.WriteHeader(http.StatusNotFound) return diff --git a/main.go b/main.go index 8ec4f69..4dbae72 100644 --- a/main.go +++ b/main.go @@ -27,6 +27,7 @@ type ServeOptions struct { port string queit bool noCors bool + tmp bool } func read(path string) *Source { @@ -98,12 +99,18 @@ func main() { Usage: "disable CORS headers", Aliases: []string{"nc"}, }, + &cli.BoolFlag{ + Name: "tmp-a", + Usage: "access to the tmp folder", + Aliases: []string{"tmp"}, + }, }, Action: func(c *cli.Context) error { host := c.String("host") port := c.String("port") quiet := c.Bool("quiet") noCors := c.Bool("no-cors") + tmp := c.Bool("tmp-a") file := c.Args().First() @@ -138,6 +145,7 @@ func main() { port: port, queit: quiet, noCors: noCors, + tmp: tmp, } serve(data, opt) diff --git a/parser.go b/parser.go index dc99491..555cc3a 100644 --- a/parser.go +++ b/parser.go @@ -11,6 +11,7 @@ import ( "io" "reflect" "strings" + "sync" "text/scanner" "unicode" @@ -18,6 +19,7 @@ import ( ) const RECORD_COUNT = 10 +const IMAGE_METHOD_KEY = "Person.Image.Name.Image.Name" type Attribute struct { Name string @@ -95,39 +97,72 @@ func parseSource(src io.Reader) []Entity { return entities } +type entityResult struct { + EntityName string + Data *[]interface{} +} + +// TODO: Map the all available funcitons instead of using reflection. Reflection is performance killer. func generateFake(entities []Entity) map[string]*[]interface{} { resultList := make(map[string]*[]interface{}) - fake := faker.New() - methodCache := make(map[string]reflect.Value) fakerValue := reflect.ValueOf(fake) + var wg sync.WaitGroup + resultsChan := make(chan entityResult, len(entities)) + for _, entity := range entities { - lowercasedEntityName := strings.ToLower(entity.Name) + wg.Add(1) + go func(entity Entity) { + defer wg.Done() + lowercasedEntityName := strings.ToLower(entity.Name) + entityResults := make([]interface{}, 0, RECORD_COUNT) + + for i := 0; i < RECORD_COUNT; i++ { + fakeValues := make(map[string]any) + + for _, attr := range entity.Attributes { + methodKey := attr.Type + method, exists := methodCache[methodKey] - entityResults := make([]interface{}, 0, RECORD_COUNT) - resultList[lowercasedEntityName] = &entityResults + if !exists { + typeParts := strings.Split(attr.Type, ".") + method = fakerValue.MethodByName(typeParts[0]) - for i := 0; i < RECORD_COUNT; i++ { - fakeValues := make(map[string]any) + for _, part := range typeParts[1:] { + method = method.Call([]reflect.Value{})[0].MethodByName(part) + methodKey += "." + part + } - for _, attr := range entity.Attributes { - methodKey := attr.Type - method, exists := methodCache[methodKey] + methodCache[methodKey] = method + } - if !exists { - typeParts := strings.Split(attr.Type, ".") - fakerMethod := fakerValue.MethodByName(typeParts[0]) - method = fakerMethod.Call([]reflect.Value{})[0].MethodByName(typeParts[1]) - methodCache[methodKey] = method + result := method.Call([]reflect.Value{})[0].Interface() + + if methodKey == IMAGE_METHOD_KEY { + result = strings.Split(result.(string), "/")[2] + } + + fakeValues[attr.Name] = result } - fakeValues[attr.Name] = method.Call([]reflect.Value{})[0].Interface() + entityResults = append(entityResults, fakeValues) } - *resultList[lowercasedEntityName] = append(*resultList[lowercasedEntityName], fakeValues) - } + resultsChan <- entityResult{EntityName: lowercasedEntityName, Data: &entityResults} + }(entity) + } + + // Close the channel after all goroutines are done + go func() { + wg.Wait() + close(resultsChan) + }() + + // Collect results + for result := range resultsChan { + resultList[result.EntityName] = result.Data } return resultList