Skip to content

Commit 243b827

Browse files
committed
feat: Add storage adapter search method
* Add search/lucene parser * Extend sql adapter with search method * Extend dynamodb adapter with search method * Extend memory adapter with search method
1 parent 336cc97 commit 243b827

5 files changed

Lines changed: 564 additions & 26 deletions

File tree

storage/dynamodb.go

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import (
1717
"github.com/aws/aws-sdk-go-v2/service/dynamodb/types"
1818

1919
"github.com/tink3rlabs/magic/logger"
20+
"github.com/tink3rlabs/magic/storage/search/lucene"
2021
)
2122

2223
type DynamoDBAdapter struct {
@@ -187,6 +188,81 @@ func (s *DynamoDBAdapter) List(dest any, sortKey string, filter map[string]any,
187188

188189
return nextToken, nil
189190
}
191+
func (s *DynamoDBAdapter) Search(dest any, sortKey string, filter string, limit int, cursor string) (string, error) {
192+
slog.Debug(fmt.Sprintf(`Searching in DynamoDB with filter: %s`, filter))
193+
194+
// Get model type from destination slice
195+
destType := reflect.TypeOf(dest).Elem().Elem()
196+
model := reflect.New(destType).Elem().Interface()
197+
198+
// Create Lucene parser from model type
199+
parser, err := lucene.NewParserFromType(model)
200+
if err != nil {
201+
slog.Error(`There was an error creating parser from model`)
202+
return "", fmt.Errorf("failed to create parser: %w", err)
203+
}
204+
205+
// Parse Lucene query to DynamoDB PartiQL
206+
whereClause, params, err := parser.ParseToDynamoDBPartiQL(filter)
207+
if err != nil {
208+
slog.Error(`There was an error parsing filter to DynamoDB PartiQL`)
209+
return "", fmt.Errorf("invalid filter: %w", err)
210+
}
211+
slog.Debug(fmt.Sprintf(`Where clause: %s`, whereClause))
212+
213+
// Build the full query
214+
query := fmt.Sprintf(`SELECT * FROM "%v"`, s.getTableName(dest))
215+
if whereClause != "" {
216+
query = query + fmt.Sprintf(` WHERE %s`, whereClause)
217+
}
218+
219+
// Add sorting if sortKey is provided
220+
if sortKey != "" {
221+
query = query + fmt.Sprintf(` ORDER BY %s`, sortKey)
222+
}
223+
224+
// Prepare the input for the ExecuteStatement operation
225+
input := dynamodb.ExecuteStatementInput{
226+
Statement: aws.String(query),
227+
Parameters: params,
228+
Limit: aws.Int32(int32(limit + 1)), // Get one extra item for cursor
229+
}
230+
231+
// Set the cursor if provided
232+
if cursor != "" {
233+
input.NextToken = aws.String(cursor)
234+
}
235+
236+
// Execute the query
237+
response, err := s.DB.ExecuteStatement(context.TODO(), &input)
238+
if err != nil {
239+
slog.Error(fmt.Sprintf(`There was an error executing query: %s`, err))
240+
return "", err
241+
}
242+
243+
// Set next token from response
244+
nextToken := ""
245+
if response.NextToken != nil {
246+
nextToken = *response.NextToken
247+
}
248+
249+
// Handle the case when we have more items than the limit
250+
if len(response.Items) > limit {
251+
// Remove the extra item
252+
response.Items = response.Items[:limit]
253+
}
254+
255+
// Unmarshal the response into the destination
256+
err = attributevalue.UnmarshalListOfMapsWithOptions(response.Items, dest, func(eo *attributevalue.DecoderOptions) {
257+
eo.TagKey = "json"
258+
})
259+
if err != nil {
260+
return "", fmt.Errorf("failed to unmarshal response: %w", err)
261+
}
262+
263+
slog.Debug(fmt.Sprintf(`Next token: %s`, nextToken))
264+
return nextToken, nil
265+
}
190266

191267
func (s *DynamoDBAdapter) getTableName(obj any) string {
192268
// Get the type of obj

storage/memory.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,3 +68,8 @@ func (m *MemoryAdapter) Delete(item any, filter map[string]any) error {
6868
func (m *MemoryAdapter) List(dest any, sortKey string, filter map[string]any, limit int, cursor string) (string, error) {
6969
return m.DB.List(dest, sortKey, filter, limit, cursor)
7070
}
71+
72+
func (m *MemoryAdapter) Search(dest any, sortKey string, query string, limit int, cursor string) (string, error) {
73+
// TODO: Finish implementation
74+
return "", nil
75+
}

0 commit comments

Comments
 (0)