Auto-indexing service and GraphQL API for AT Protocol Records
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

format

+643 -617
+71 -61
client/src/generated/queries.gleam
··· 4 4 /// This function is auto-generated by Squall 5 5 pub fn init_registry() -> unstable_registry.Registry { 6 6 let reg = unstable_registry.new() 7 - let reg = unstable_registry.register( 8 - reg, 9 - "TriggerBackfill", 10 - "mutation TriggerBackfill {\n triggerBackfill\n}", 11 - "generated/queries/trigger_backfill", 12 - ) 13 - let reg = unstable_registry.register( 14 - reg, 15 - "GetCurrentSession", 16 - "query GetCurrentSession {\n currentSession {\n __typename\n did\n handle\n isAdmin\n }\n}", 17 - "generated/queries/get_current_session", 18 - ) 19 - let reg = unstable_registry.register( 20 - reg, 21 - "GetActivityBuckets", 22 - "query GetActivityBuckets($range: TimeRange!) {\n activityBuckets(range: $range) {\n __typename\n timestamp\n total\n creates\n updates\n deletes\n }\n}", 23 - "generated/queries/get_activity_buckets", 24 - ) 25 - let reg = unstable_registry.register( 26 - reg, 27 - "GetRecentActivity", 28 - "query GetRecentActivity($hours: Int!) {\n recentActivity(hours: $hours) {\n __typename\n id\n timestamp\n operation\n collection\n did\n status\n errorMessage\n eventJson\n }\n}", 29 - "generated/queries/get_recent_activity", 30 - ) 31 - let reg = unstable_registry.register( 32 - reg, 33 - "GetStatistics", 34 - "query GetStatistics {\n statistics {\n __typename\n recordCount\n actorCount\n lexiconCount\n }\n}", 35 - "generated/queries/get_statistics", 36 - ) 37 - let reg = unstable_registry.register( 38 - reg, 39 - "GetSettings", 40 - "query GetSettings {\n settings {\n __typename\n id\n domainAuthority\n oauthClientId\n }\n}", 41 - "generated/queries/get_settings", 42 - ) 43 - let reg = unstable_registry.register( 44 - reg, 45 - "UpdateDomainAuthority", 46 - "mutation UpdateDomainAuthority($domainAuthority: String!) {\n updateDomainAuthority(domainAuthority: $domainAuthority) {\n __typename\n id\n domainAuthority\n oauthClientId\n }\n}", 47 - "generated/queries/update_domain_authority", 48 - ) 49 - let reg = unstable_registry.register( 50 - reg, 51 - "UploadLexicons", 52 - "mutation UploadLexicons($zipBase64: String!) {\n uploadLexicons(zipBase64: $zipBase64)\n}", 53 - "generated/queries/upload_lexicons", 54 - ) 55 - let reg = unstable_registry.register( 56 - reg, 57 - "ResetAll", 58 - "mutation ResetAll($confirm: String!) {\n resetAll(confirm: $confirm)\n}", 59 - "generated/queries/reset_all", 60 - ) 61 - let reg = unstable_registry.register( 62 - reg, 63 - "GetLexicons", 64 - "query GetLexicons {\n lexicons {\n __typename\n id\n json\n createdAt\n }\n}", 65 - "generated/queries/get_lexicons", 66 - ) 7 + let reg = 8 + unstable_registry.register( 9 + reg, 10 + "TriggerBackfill", 11 + "mutation TriggerBackfill {\n triggerBackfill\n}", 12 + "generated/queries/trigger_backfill", 13 + ) 14 + let reg = 15 + unstable_registry.register( 16 + reg, 17 + "GetCurrentSession", 18 + "query GetCurrentSession {\n currentSession {\n __typename\n did\n handle\n isAdmin\n }\n}", 19 + "generated/queries/get_current_session", 20 + ) 21 + let reg = 22 + unstable_registry.register( 23 + reg, 24 + "GetActivityBuckets", 25 + "query GetActivityBuckets($range: TimeRange!) {\n activityBuckets(range: $range) {\n __typename\n timestamp\n total\n creates\n updates\n deletes\n }\n}", 26 + "generated/queries/get_activity_buckets", 27 + ) 28 + let reg = 29 + unstable_registry.register( 30 + reg, 31 + "GetRecentActivity", 32 + "query GetRecentActivity($hours: Int!) {\n recentActivity(hours: $hours) {\n __typename\n id\n timestamp\n operation\n collection\n did\n status\n errorMessage\n eventJson\n }\n}", 33 + "generated/queries/get_recent_activity", 34 + ) 35 + let reg = 36 + unstable_registry.register( 37 + reg, 38 + "GetStatistics", 39 + "query GetStatistics {\n statistics {\n __typename\n recordCount\n actorCount\n lexiconCount\n }\n}", 40 + "generated/queries/get_statistics", 41 + ) 42 + let reg = 43 + unstable_registry.register( 44 + reg, 45 + "GetSettings", 46 + "query GetSettings {\n settings {\n __typename\n id\n domainAuthority\n oauthClientId\n }\n}", 47 + "generated/queries/get_settings", 48 + ) 49 + let reg = 50 + unstable_registry.register( 51 + reg, 52 + "UpdateDomainAuthority", 53 + "mutation UpdateDomainAuthority($domainAuthority: String!) {\n updateDomainAuthority(domainAuthority: $domainAuthority) {\n __typename\n id\n domainAuthority\n oauthClientId\n }\n}", 54 + "generated/queries/update_domain_authority", 55 + ) 56 + let reg = 57 + unstable_registry.register( 58 + reg, 59 + "UploadLexicons", 60 + "mutation UploadLexicons($zipBase64: String!) {\n uploadLexicons(zipBase64: $zipBase64)\n}", 61 + "generated/queries/upload_lexicons", 62 + ) 63 + let reg = 64 + unstable_registry.register( 65 + reg, 66 + "ResetAll", 67 + "mutation ResetAll($confirm: String!) {\n resetAll(confirm: $confirm)\n}", 68 + "generated/queries/reset_all", 69 + ) 70 + let reg = 71 + unstable_registry.register( 72 + reg, 73 + "GetLexicons", 74 + "query GetLexicons {\n lexicons {\n __typename\n id\n json\n createdAt\n }\n}", 75 + "generated/queries/get_lexicons", 76 + ) 67 77 reg 68 - } 78 + }
+30 -27
client/src/generated/queries/get_activity_buckets.gleam
··· 23 23 24 24 pub fn time_range_decoder() -> decode.Decoder(TimeRange) { 25 25 decode.string 26 - 27 - 28 26 |> decode.then(fn(str) { 29 - 30 27 case str { 31 28 "ONE_HOUR" -> decode.success(ONEHOUR) 32 29 "THREE_HOURS" -> decode.success(THREEHOURS) ··· 35 32 "SEVEN_DAYS" -> decode.success(SEVENDAYS) 36 33 _other -> decode.failure(ONEHOUR, "TimeRange") 37 34 } 38 - 39 - 40 35 }) 41 36 } 42 37 ··· 66 61 } 67 62 68 63 pub fn activity_bucket_to_json(input: ActivityBucket) -> json.Json { 69 - json.object( 70 - [ 71 - #("timestamp", json.string(input.timestamp)), 72 - #("total", json.int(input.total)), 73 - #("creates", json.int(input.creates)), 74 - #("updates", json.int(input.updates)), 75 - #("deletes", json.int(input.deletes)), 76 - ], 77 - ) 64 + json.object([ 65 + #("timestamp", json.string(input.timestamp)), 66 + #("total", json.int(input.total)), 67 + #("creates", json.int(input.creates)), 68 + #("updates", json.int(input.updates)), 69 + #("deletes", json.int(input.deletes)), 70 + ]) 78 71 } 79 72 80 73 pub type GetActivityBucketsResponse { 81 74 GetActivityBucketsResponse(activity_buckets: List(ActivityBucket)) 82 75 } 83 76 84 - pub fn get_activity_buckets_response_decoder() -> decode.Decoder(GetActivityBucketsResponse) { 85 - use activity_buckets <- decode.field("activityBuckets", decode.list(activity_bucket_decoder())) 77 + pub fn get_activity_buckets_response_decoder() -> decode.Decoder( 78 + GetActivityBucketsResponse, 79 + ) { 80 + use activity_buckets <- decode.field( 81 + "activityBuckets", 82 + decode.list(activity_bucket_decoder()), 83 + ) 86 84 decode.success(GetActivityBucketsResponse(activity_buckets: activity_buckets)) 87 85 } 88 86 89 - pub fn get_activity_buckets_response_to_json(input: GetActivityBucketsResponse) -> json.Json { 90 - json.object( 91 - [ 92 - #("activityBuckets", json.array( 93 - from: input.activity_buckets, 94 - of: activity_bucket_to_json, 95 - )), 96 - ], 97 - ) 87 + pub fn get_activity_buckets_response_to_json( 88 + input: GetActivityBucketsResponse, 89 + ) -> json.Json { 90 + json.object([ 91 + #( 92 + "activityBuckets", 93 + json.array(from: input.activity_buckets, of: activity_bucket_to_json), 94 + ), 95 + ]) 98 96 } 99 97 100 - pub fn get_activity_buckets(client: squall.Client, range: TimeRange) -> Result(Request(String), String) { 98 + pub fn get_activity_buckets( 99 + client: squall.Client, 100 + range: TimeRange, 101 + ) -> Result(Request(String), String) { 101 102 squall.prepare_request( 102 103 client, 103 104 "query GetActivityBuckets($range: TimeRange!) {\n activityBuckets(range: $range) {\n timestamp\n total\n creates\n updates\n deletes\n }\n}", ··· 105 106 ) 106 107 } 107 108 108 - pub fn parse_get_activity_buckets_response(body: String) -> Result(GetActivityBucketsResponse, String) { 109 + pub fn parse_get_activity_buckets_response( 110 + body: String, 111 + ) -> Result(GetActivityBucketsResponse, String) { 109 112 squall.parse_response(body, get_activity_buckets_response_decoder()) 110 113 }
+28 -21
client/src/generated/queries/get_current_session.gleam
··· 1 1 import gleam/dynamic/decode 2 2 import gleam/http/request.{type Request} 3 3 import gleam/json 4 - import squall 5 4 import gleam/option.{type Option} 5 + import squall 6 6 7 7 pub type CurrentSession { 8 8 CurrentSession(did: String, handle: String, is_admin: Bool) ··· 16 16 } 17 17 18 18 pub fn current_session_to_json(input: CurrentSession) -> json.Json { 19 - json.object( 20 - [ 21 - #("did", json.string(input.did)), 22 - #("handle", json.string(input.handle)), 23 - #("isAdmin", json.bool(input.is_admin)), 24 - ], 25 - ) 19 + json.object([ 20 + #("did", json.string(input.did)), 21 + #("handle", json.string(input.handle)), 22 + #("isAdmin", json.bool(input.is_admin)), 23 + ]) 26 24 } 27 25 28 26 pub type GetCurrentSessionResponse { 29 27 GetCurrentSessionResponse(current_session: Option(CurrentSession)) 30 28 } 31 29 32 - pub fn get_current_session_response_decoder() -> decode.Decoder(GetCurrentSessionResponse) { 33 - use current_session <- decode.field("currentSession", decode.optional(current_session_decoder())) 30 + pub fn get_current_session_response_decoder() -> decode.Decoder( 31 + GetCurrentSessionResponse, 32 + ) { 33 + use current_session <- decode.field( 34 + "currentSession", 35 + decode.optional(current_session_decoder()), 36 + ) 34 37 decode.success(GetCurrentSessionResponse(current_session: current_session)) 35 38 } 36 39 37 - pub fn get_current_session_response_to_json(input: GetCurrentSessionResponse) -> json.Json { 38 - json.object( 39 - [ 40 - #("currentSession", json.nullable( 41 - input.current_session, 42 - current_session_to_json, 43 - )), 44 - ], 45 - ) 40 + pub fn get_current_session_response_to_json( 41 + input: GetCurrentSessionResponse, 42 + ) -> json.Json { 43 + json.object([ 44 + #( 45 + "currentSession", 46 + json.nullable(input.current_session, current_session_to_json), 47 + ), 48 + ]) 46 49 } 47 50 48 - pub fn get_current_session(client: squall.Client) -> Result(Request(String), String) { 51 + pub fn get_current_session( 52 + client: squall.Client, 53 + ) -> Result(Request(String), String) { 49 54 squall.prepare_request( 50 55 client, 51 56 "query GetCurrentSession {\n currentSession {\n did\n handle\n isAdmin\n }\n}", ··· 53 58 ) 54 59 } 55 60 56 - pub fn parse_get_current_session_response(body: String) -> Result(GetCurrentSessionResponse, String) { 61 + pub fn parse_get_current_session_response( 62 + body: String, 63 + ) -> Result(GetCurrentSessionResponse, String) { 57 64 squall.parse_response(body, get_current_session_response_decoder()) 58 65 }
+11 -13
client/src/generated/queries/get_lexicons.gleam
··· 15 15 } 16 16 17 17 pub fn lexicon_to_json(input: Lexicon) -> json.Json { 18 - json.object( 19 - [ 20 - #("id", json.string(input.id)), 21 - #("json", json.string(input.json)), 22 - #("createdAt", json.string(input.created_at)), 23 - ], 24 - ) 18 + json.object([ 19 + #("id", json.string(input.id)), 20 + #("json", json.string(input.json)), 21 + #("createdAt", json.string(input.created_at)), 22 + ]) 25 23 } 26 24 27 25 pub type GetLexiconsResponse { ··· 34 32 } 35 33 36 34 pub fn get_lexicons_response_to_json(input: GetLexiconsResponse) -> json.Json { 37 - json.object( 38 - [ 39 - #("lexicons", json.array(from: input.lexicons, of: lexicon_to_json)), 40 - ], 41 - ) 35 + json.object([ 36 + #("lexicons", json.array(from: input.lexicons, of: lexicon_to_json)), 37 + ]) 42 38 } 43 39 44 40 pub fn get_lexicons(client: squall.Client) -> Result(Request(String), String) { ··· 49 45 ) 50 46 } 51 47 52 - pub fn parse_get_lexicons_response(body: String) -> Result(GetLexiconsResponse, String) { 48 + pub fn parse_get_lexicons_response( 49 + body: String, 50 + ) -> Result(GetLexiconsResponse, String) { 53 51 squall.parse_response(body, get_lexicons_response_decoder()) 54 52 }
+38 -27
client/src/generated/queries/get_recent_activity.gleam
··· 1 1 import gleam/dynamic/decode 2 2 import gleam/http/request.{type Request} 3 3 import gleam/json 4 - import squall 5 4 import gleam/option.{type Option} 5 + import squall 6 6 7 7 pub type ActivityEntry { 8 8 ActivityEntry( ··· 24 24 use collection <- decode.field("collection", decode.string) 25 25 use did <- decode.field("did", decode.string) 26 26 use status <- decode.field("status", decode.string) 27 - use error_message <- decode.field("errorMessage", decode.optional(decode.string)) 27 + use error_message <- decode.field( 28 + "errorMessage", 29 + decode.optional(decode.string), 30 + ) 28 31 use event_json <- decode.field("eventJson", decode.optional(decode.string)) 29 32 decode.success(ActivityEntry( 30 33 id: id, ··· 39 42 } 40 43 41 44 pub fn activity_entry_to_json(input: ActivityEntry) -> json.Json { 42 - json.object( 43 - [ 44 - #("id", json.int(input.id)), 45 - #("timestamp", json.string(input.timestamp)), 46 - #("operation", json.string(input.operation)), 47 - #("collection", json.string(input.collection)), 48 - #("did", json.string(input.did)), 49 - #("status", json.string(input.status)), 50 - #("errorMessage", json.nullable(input.error_message, json.string)), 51 - #("eventJson", json.nullable(input.event_json, json.string)), 52 - ], 53 - ) 45 + json.object([ 46 + #("id", json.int(input.id)), 47 + #("timestamp", json.string(input.timestamp)), 48 + #("operation", json.string(input.operation)), 49 + #("collection", json.string(input.collection)), 50 + #("did", json.string(input.did)), 51 + #("status", json.string(input.status)), 52 + #("errorMessage", json.nullable(input.error_message, json.string)), 53 + #("eventJson", json.nullable(input.event_json, json.string)), 54 + ]) 54 55 } 55 56 56 57 pub type GetRecentActivityResponse { 57 58 GetRecentActivityResponse(recent_activity: List(ActivityEntry)) 58 59 } 59 60 60 - pub fn get_recent_activity_response_decoder() -> decode.Decoder(GetRecentActivityResponse) { 61 - use recent_activity <- decode.field("recentActivity", decode.list(activity_entry_decoder())) 61 + pub fn get_recent_activity_response_decoder() -> decode.Decoder( 62 + GetRecentActivityResponse, 63 + ) { 64 + use recent_activity <- decode.field( 65 + "recentActivity", 66 + decode.list(activity_entry_decoder()), 67 + ) 62 68 decode.success(GetRecentActivityResponse(recent_activity: recent_activity)) 63 69 } 64 70 65 - pub fn get_recent_activity_response_to_json(input: GetRecentActivityResponse) -> json.Json { 66 - json.object( 67 - [ 68 - #("recentActivity", json.array( 69 - from: input.recent_activity, 70 - of: activity_entry_to_json, 71 - )), 72 - ], 73 - ) 71 + pub fn get_recent_activity_response_to_json( 72 + input: GetRecentActivityResponse, 73 + ) -> json.Json { 74 + json.object([ 75 + #( 76 + "recentActivity", 77 + json.array(from: input.recent_activity, of: activity_entry_to_json), 78 + ), 79 + ]) 74 80 } 75 81 76 - pub fn get_recent_activity(client: squall.Client, hours: Int) -> Result(Request(String), String) { 82 + pub fn get_recent_activity( 83 + client: squall.Client, 84 + hours: Int, 85 + ) -> Result(Request(String), String) { 77 86 squall.prepare_request( 78 87 client, 79 88 "query GetRecentActivity($hours: Int!) {\n recentActivity(hours: $hours) {\n id\n timestamp\n operation\n collection\n did\n status\n errorMessage\n eventJson\n }\n}", ··· 81 90 ) 82 91 } 83 92 84 - pub fn parse_get_recent_activity_response(body: String) -> Result(GetRecentActivityResponse, String) { 93 + pub fn parse_get_recent_activity_response( 94 + body: String, 95 + ) -> Result(GetRecentActivityResponse, String) { 85 96 squall.parse_response(body, get_recent_activity_response_decoder()) 86 97 }
+13 -10
client/src/generated/queries/get_settings.gleam
··· 1 1 import gleam/dynamic/decode 2 2 import gleam/http/request.{type Request} 3 3 import gleam/json 4 - import squall 5 4 import gleam/option.{type Option} 5 + import squall 6 6 7 7 pub type Settings { 8 8 Settings( ··· 15 15 pub fn settings_decoder() -> decode.Decoder(Settings) { 16 16 use id <- decode.field("id", decode.string) 17 17 use domain_authority <- decode.field("domainAuthority", decode.string) 18 - use oauth_client_id <- decode.field("oauthClientId", decode.optional(decode.string)) 18 + use oauth_client_id <- decode.field( 19 + "oauthClientId", 20 + decode.optional(decode.string), 21 + ) 19 22 decode.success(Settings( 20 23 id: id, 21 24 domain_authority: domain_authority, ··· 24 27 } 25 28 26 29 pub fn settings_to_json(input: Settings) -> json.Json { 27 - json.object( 28 - [ 29 - #("id", json.string(input.id)), 30 - #("domainAuthority", json.string(input.domain_authority)), 31 - #("oauthClientId", json.nullable(input.oauth_client_id, json.string)), 32 - ], 33 - ) 30 + json.object([ 31 + #("id", json.string(input.id)), 32 + #("domainAuthority", json.string(input.domain_authority)), 33 + #("oauthClientId", json.nullable(input.oauth_client_id, json.string)), 34 + ]) 34 35 } 35 36 36 37 pub type GetSettingsResponse { ··· 54 55 ) 55 56 } 56 57 57 - pub fn parse_get_settings_response(body: String) -> Result(GetSettingsResponse, String) { 58 + pub fn parse_get_settings_response( 59 + body: String, 60 + ) -> Result(GetSettingsResponse, String) { 58 61 squall.parse_response(body, get_settings_response_decoder()) 59 62 }
+14 -10
client/src/generated/queries/get_statistics.gleam
··· 19 19 } 20 20 21 21 pub fn statistics_to_json(input: Statistics) -> json.Json { 22 - json.object( 23 - [ 24 - #("recordCount", json.int(input.record_count)), 25 - #("actorCount", json.int(input.actor_count)), 26 - #("lexiconCount", json.int(input.lexicon_count)), 27 - ], 28 - ) 22 + json.object([ 23 + #("recordCount", json.int(input.record_count)), 24 + #("actorCount", json.int(input.actor_count)), 25 + #("lexiconCount", json.int(input.lexicon_count)), 26 + ]) 29 27 } 30 28 31 29 pub type GetStatisticsResponse { 32 30 GetStatisticsResponse(statistics: Statistics) 33 31 } 34 32 35 - pub fn get_statistics_response_decoder() -> decode.Decoder(GetStatisticsResponse) { 33 + pub fn get_statistics_response_decoder() -> decode.Decoder( 34 + GetStatisticsResponse, 35 + ) { 36 36 use statistics <- decode.field("statistics", statistics_decoder()) 37 37 decode.success(GetStatisticsResponse(statistics: statistics)) 38 38 } 39 39 40 - pub fn get_statistics_response_to_json(input: GetStatisticsResponse) -> json.Json { 40 + pub fn get_statistics_response_to_json( 41 + input: GetStatisticsResponse, 42 + ) -> json.Json { 41 43 json.object([#("statistics", statistics_to_json(input.statistics))]) 42 44 } 43 45 ··· 49 51 ) 50 52 } 51 53 52 - pub fn parse_get_statistics_response(body: String) -> Result(GetStatisticsResponse, String) { 54 + pub fn parse_get_statistics_response( 55 + body: String, 56 + ) -> Result(GetStatisticsResponse, String) { 53 57 squall.parse_response(body, get_statistics_response_decoder()) 54 58 }
+7 -2
client/src/generated/queries/reset_all.gleam
··· 16 16 json.object([#("resetAll", json.bool(input.reset_all))]) 17 17 } 18 18 19 - pub fn reset_all(client: squall.Client, confirm: String) -> Result(Request(String), String) { 19 + pub fn reset_all( 20 + client: squall.Client, 21 + confirm: String, 22 + ) -> Result(Request(String), String) { 20 23 squall.prepare_request( 21 24 client, 22 25 "mutation ResetAll($confirm: String!) {\n resetAll(confirm: $confirm)\n}", ··· 24 27 ) 25 28 } 26 29 27 - pub fn parse_reset_all_response(body: String) -> Result(ResetAllResponse, String) { 30 + pub fn parse_reset_all_response( 31 + body: String, 32 + ) -> Result(ResetAllResponse, String) { 28 33 squall.parse_response(body, reset_all_response_decoder()) 29 34 }
+12 -4
client/src/generated/queries/trigger_backfill.gleam
··· 7 7 TriggerBackfillResponse(trigger_backfill: Bool) 8 8 } 9 9 10 - pub fn trigger_backfill_response_decoder() -> decode.Decoder(TriggerBackfillResponse) { 10 + pub fn trigger_backfill_response_decoder() -> decode.Decoder( 11 + TriggerBackfillResponse, 12 + ) { 11 13 use trigger_backfill <- decode.field("triggerBackfill", decode.bool) 12 14 decode.success(TriggerBackfillResponse(trigger_backfill: trigger_backfill)) 13 15 } 14 16 15 - pub fn trigger_backfill_response_to_json(input: TriggerBackfillResponse) -> json.Json { 17 + pub fn trigger_backfill_response_to_json( 18 + input: TriggerBackfillResponse, 19 + ) -> json.Json { 16 20 json.object([#("triggerBackfill", json.bool(input.trigger_backfill))]) 17 21 } 18 22 19 - pub fn trigger_backfill(client: squall.Client) -> Result(Request(String), String) { 23 + pub fn trigger_backfill( 24 + client: squall.Client, 25 + ) -> Result(Request(String), String) { 20 26 squall.prepare_request( 21 27 client, 22 28 "mutation TriggerBackfill {\n triggerBackfill\n}", ··· 24 30 ) 25 31 } 26 32 27 - pub fn parse_trigger_backfill_response(body: String) -> Result(TriggerBackfillResponse, String) { 33 + pub fn parse_trigger_backfill_response( 34 + body: String, 35 + ) -> Result(TriggerBackfillResponse, String) { 28 36 squall.parse_response(body, trigger_backfill_response_decoder()) 29 37 }
+30 -19
client/src/generated/queries/update_domain_authority.gleam
··· 1 1 import gleam/dynamic/decode 2 2 import gleam/http/request.{type Request} 3 3 import gleam/json 4 - import squall 5 4 import gleam/option.{type Option} 5 + import squall 6 6 7 7 pub type Settings { 8 8 Settings( ··· 15 15 pub fn settings_decoder() -> decode.Decoder(Settings) { 16 16 use id <- decode.field("id", decode.string) 17 17 use domain_authority <- decode.field("domainAuthority", decode.string) 18 - use oauth_client_id <- decode.field("oauthClientId", decode.optional(decode.string)) 18 + use oauth_client_id <- decode.field( 19 + "oauthClientId", 20 + decode.optional(decode.string), 21 + ) 19 22 decode.success(Settings( 20 23 id: id, 21 24 domain_authority: domain_authority, ··· 24 27 } 25 28 26 29 pub fn settings_to_json(input: Settings) -> json.Json { 27 - json.object( 28 - [ 29 - #("id", json.string(input.id)), 30 - #("domainAuthority", json.string(input.domain_authority)), 31 - #("oauthClientId", json.nullable(input.oauth_client_id, json.string)), 32 - ], 33 - ) 30 + json.object([ 31 + #("id", json.string(input.id)), 32 + #("domainAuthority", json.string(input.domain_authority)), 33 + #("oauthClientId", json.nullable(input.oauth_client_id, json.string)), 34 + ]) 34 35 } 35 36 36 37 pub type UpdateDomainAuthorityResponse { 37 38 UpdateDomainAuthorityResponse(update_domain_authority: Settings) 38 39 } 39 40 40 - pub fn update_domain_authority_response_decoder() -> decode.Decoder(UpdateDomainAuthorityResponse) { 41 - use update_domain_authority <- decode.field("updateDomainAuthority", settings_decoder()) 41 + pub fn update_domain_authority_response_decoder() -> decode.Decoder( 42 + UpdateDomainAuthorityResponse, 43 + ) { 44 + use update_domain_authority <- decode.field( 45 + "updateDomainAuthority", 46 + settings_decoder(), 47 + ) 42 48 decode.success(UpdateDomainAuthorityResponse( 43 49 update_domain_authority: update_domain_authority, 44 50 )) 45 51 } 46 52 47 - pub fn update_domain_authority_response_to_json(input: UpdateDomainAuthorityResponse) -> json.Json { 48 - json.object( 49 - [ 50 - #("updateDomainAuthority", settings_to_json(input.update_domain_authority)), 51 - ], 52 - ) 53 + pub fn update_domain_authority_response_to_json( 54 + input: UpdateDomainAuthorityResponse, 55 + ) -> json.Json { 56 + json.object([ 57 + #("updateDomainAuthority", settings_to_json(input.update_domain_authority)), 58 + ]) 53 59 } 54 60 55 - pub fn update_domain_authority(client: squall.Client, domain_authority: String) -> Result(Request(String), String) { 61 + pub fn update_domain_authority( 62 + client: squall.Client, 63 + domain_authority: String, 64 + ) -> Result(Request(String), String) { 56 65 squall.prepare_request( 57 66 client, 58 67 "mutation UpdateDomainAuthority($domainAuthority: String!) {\n updateDomainAuthority(domainAuthority: $domainAuthority) {\n id\n domainAuthority\n oauthClientId\n }\n}", ··· 60 69 ) 61 70 } 62 71 63 - pub fn parse_update_domain_authority_response(body: String) -> Result(UpdateDomainAuthorityResponse, String) { 72 + pub fn parse_update_domain_authority_response( 73 + body: String, 74 + ) -> Result(UpdateDomainAuthorityResponse, String) { 64 75 squall.parse_response(body, update_domain_authority_response_decoder()) 65 76 }
+13 -4
client/src/generated/queries/upload_lexicons.gleam
··· 7 7 UploadLexiconsResponse(upload_lexicons: Bool) 8 8 } 9 9 10 - pub fn upload_lexicons_response_decoder() -> decode.Decoder(UploadLexiconsResponse) { 10 + pub fn upload_lexicons_response_decoder() -> decode.Decoder( 11 + UploadLexiconsResponse, 12 + ) { 11 13 use upload_lexicons <- decode.field("uploadLexicons", decode.bool) 12 14 decode.success(UploadLexiconsResponse(upload_lexicons: upload_lexicons)) 13 15 } 14 16 15 - pub fn upload_lexicons_response_to_json(input: UploadLexiconsResponse) -> json.Json { 17 + pub fn upload_lexicons_response_to_json( 18 + input: UploadLexiconsResponse, 19 + ) -> json.Json { 16 20 json.object([#("uploadLexicons", json.bool(input.upload_lexicons))]) 17 21 } 18 22 19 - pub fn upload_lexicons(client: squall.Client, zip_base64: String) -> Result(Request(String), String) { 23 + pub fn upload_lexicons( 24 + client: squall.Client, 25 + zip_base64: String, 26 + ) -> Result(Request(String), String) { 20 27 squall.prepare_request( 21 28 client, 22 29 "mutation UploadLexicons($zipBase64: String!) {\n uploadLexicons(zipBase64: $zipBase64)\n}", ··· 24 31 ) 25 32 } 26 33 27 - pub fn parse_upload_lexicons_response(body: String) -> Result(UploadLexiconsResponse, String) { 34 + pub fn parse_upload_lexicons_response( 35 + body: String, 36 + ) -> Result(UploadLexiconsResponse, String) { 28 37 squall.parse_response(body, upload_lexicons_response_decoder()) 29 38 }
+10 -11
client/src/json_highlighter.gleam
··· 61 61 ..acc 62 62 ]) 63 63 } 64 - ["{", ..rest] | ["}", ..rest] | ["[", ..rest] | ["]", ..rest] 65 - if !in_string 66 - -> { 64 + ["{", ..rest] | ["}", ..rest] | ["[", ..rest] | ["]", ..rest] if !in_string -> { 67 65 // Structural characters - dimmed white 68 66 let char = case chars { 69 67 [c, ..] -> c ··· 85 83 } 86 84 [" ", ..rest] | ["\n", ..rest] if !in_string -> { 87 85 // Preserve whitespace and maintain after_colon state 88 - let elem = element.text(case chars { 89 - [" ", ..] -> " " 90 - ["\n", ..] -> "\n" 91 - _ -> "" 92 - }) 86 + let elem = 87 + element.text(case chars { 88 + [" ", ..] -> " " 89 + ["\n", ..] -> "\n" 90 + _ -> "" 91 + }) 93 92 highlight_chars_with_context(rest, in_string, after_colon, [elem, ..acc]) 94 93 } 95 94 [char, ..rest] if in_string -> { ··· 101 100 let elem = html.span([attribute.class(color)], [element.text(char)]) 102 101 highlight_chars_with_context(rest, in_string, after_colon, [elem, ..acc]) 103 102 } 104 - ["t", "r", "u", "e", .._rest] 105 - | ["f", "a", "l", "s", "e", .._rest] 106 - | ["n", "u", "l", "l", .._rest] 103 + ["t", "r", "u", "e", ..] 104 + | ["f", "a", "l", "s", "e", ..] 105 + | ["n", "u", "l", "l", ..] 107 106 if !in_string 108 107 -> { 109 108 // Boolean or null - sunset red
+5 -5
client/src/pages/lexicons.gleam
··· 88 88 ]) 89 89 } 90 90 91 - fn render_lexicons( 92 - lexicons: List(get_lexicons.Lexicon), 93 - ) -> Element(Msg) { 91 + fn render_lexicons(lexicons: List(get_lexicons.Lexicon)) -> Element(Msg) { 94 92 case lexicons { 95 93 [] -> render_empty() 96 94 _ -> ··· 98 96 html.p([attribute.class("text-sm text-zinc-500 mb-4")], [ 99 97 element.text(string.inspect(list.length(lexicons)) <> " lexicons"), 100 98 ]), 101 - html.div([attribute.class("space-y-3")], list.map(lexicons, render_lexicon)), 99 + html.div( 100 + [attribute.class("space-y-3")], 101 + list.map(lexicons, render_lexicon), 102 + ), 102 103 ]) 103 104 } 104 105 } ··· 157 158 ]), 158 159 ]) 159 160 } 160 -
+2 -2
lexicon_graphql/src/lexicon_graphql/internal/graphql/object_builder.gleam
··· 7 7 import gleam/list 8 8 import gleam/option 9 9 import gleam/string 10 - import lexicon_graphql/internal/lexicon/registry as lexicon_registry 11 - import lexicon_graphql/internal/lexicon/nsid 12 10 import lexicon_graphql/internal/graphql/type_mapper 11 + import lexicon_graphql/internal/lexicon/nsid 12 + import lexicon_graphql/internal/lexicon/registry as lexicon_registry 13 13 import lexicon_graphql/types 14 14 import swell/schema 15 15 import swell/value
+4 -16
lexicon_graphql/src/lexicon_graphql/mutation/builder.gleam
··· 8 8 import gleam/dict 9 9 import gleam/list 10 10 import gleam/option 11 - import lexicon_graphql/internal/lexicon/nsid 12 11 import lexicon_graphql/internal/graphql/type_mapper 12 + import lexicon_graphql/internal/lexicon/nsid 13 13 import lexicon_graphql/types 14 14 import swell/schema 15 15 import swell/value ··· 150 150 let resolver = case factory { 151 151 option.Some(factory_fn) -> factory_fn(collection) 152 152 option.None -> fn(_resolver_ctx) { 153 - Error( 154 - "Create mutation for " 155 - <> collection 156 - <> " not yet implemented.", 157 - ) 153 + Error("Create mutation for " <> collection <> " not yet implemented.") 158 154 } 159 155 } 160 156 ··· 205 201 let resolver = case factory { 206 202 option.Some(factory_fn) -> factory_fn(collection) 207 203 option.None -> fn(_resolver_ctx) { 208 - Error( 209 - "Update mutation for " 210 - <> collection 211 - <> " not yet implemented.", 212 - ) 204 + Error("Update mutation for " <> collection <> " not yet implemented.") 213 205 } 214 206 } 215 207 ··· 249 241 let resolver = case factory { 250 242 option.Some(factory_fn) -> factory_fn(collection) 251 243 option.None -> fn(_resolver_ctx) { 252 - Error( 253 - "Delete mutation for " 254 - <> collection 255 - <> " not yet implemented.", 256 - ) 244 + Error("Delete mutation for " <> collection <> " not yet implemented.") 257 245 } 258 246 } 259 247
+1 -1
lexicon_graphql/src/lexicon_graphql/query/dataloader.gleam
··· 8 8 import gleam/option.{type Option, None, Some} 9 9 import gleam/result 10 10 import gleam/string 11 + import lexicon_graphql/input/where.{type WhereClause} 11 12 import lexicon_graphql/internal/lexicon/collection_meta 12 13 import lexicon_graphql/internal/lexicon/uri_extractor 13 - import lexicon_graphql/input/where.{type WhereClause} 14 14 import swell/value 15 15 16 16 /// Result of a batch query: maps URIs to their records
+2 -2
lexicon_graphql/src/lexicon_graphql/schema/builder.gleam
··· 5 5 import gleam/dict 6 6 import gleam/list 7 7 import gleam/option 8 - import lexicon_graphql/mutation/builder as mutation_builder 9 - import lexicon_graphql/internal/lexicon/nsid 10 8 import lexicon_graphql/internal/graphql/type_mapper 9 + import lexicon_graphql/internal/lexicon/nsid 10 + import lexicon_graphql/mutation/builder as mutation_builder 11 11 import lexicon_graphql/types 12 12 import swell/schema 13 13 import swell/value
+14 -10
lexicon_graphql/src/lexicon_graphql/schema/database.gleam
··· 12 12 import gleam/result 13 13 import gleam/string 14 14 import lexicon_graphql/input/aggregate as aggregate_input 15 - import lexicon_graphql/output/aggregate as aggregate_types 16 - import lexicon_graphql/internal/lexicon/collection_meta 17 15 import lexicon_graphql/input/connection as lexicon_connection 18 - import lexicon_graphql/query/dataloader 19 - import lexicon_graphql/internal/lexicon/registry as lexicon_registry 20 - import lexicon_graphql/mutation/builder as mutation_builder 21 - import lexicon_graphql/internal/lexicon/nsid 16 + import lexicon_graphql/input/where as where_input 22 17 import lexicon_graphql/internal/graphql/object_builder as object_type_builder 23 18 import lexicon_graphql/internal/graphql/type_mapper 24 - import lexicon_graphql/types 19 + import lexicon_graphql/internal/lexicon/collection_meta 20 + import lexicon_graphql/internal/lexicon/nsid 21 + import lexicon_graphql/internal/lexicon/registry as lexicon_registry 25 22 import lexicon_graphql/internal/lexicon/uri_extractor 26 - import lexicon_graphql/input/where as where_input 23 + import lexicon_graphql/mutation/builder as mutation_builder 24 + import lexicon_graphql/output/aggregate as aggregate_types 25 + import lexicon_graphql/query/dataloader 26 + import lexicon_graphql/types 27 27 import swell/connection 28 28 import swell/schema 29 29 import swell/value ··· 1284 1284 /// Non-groupable types: blob, ref (complex types) 1285 1285 fn is_groupable_property(property: types.Property) -> Bool { 1286 1286 case property_to_field_type(property) { 1287 - StringField | IntField | BoolField | NumberField | DateTimeField | ArrayField -> 1288 - True 1287 + StringField 1288 + | IntField 1289 + | BoolField 1290 + | NumberField 1291 + | DateTimeField 1292 + | ArrayField -> True 1289 1293 BlobField | RefField -> False 1290 1294 } 1291 1295 }
+1 -1
lexicon_graphql/test/collection_meta_test.gleam
··· 4 4 import gleam/dict 5 5 import gleam/option.{None, Some} 6 6 import gleeunit/should 7 - import lexicon_graphql/internal/lexicon/collection_meta as collection_meta 7 + import lexicon_graphql/internal/lexicon/collection_meta 8 8 import lexicon_graphql/types 9 9 10 10 // Test extracting metadata from a lexicon with strongRef fields
+1 -1
lexicon_graphql/test/dataloader_test.gleam
··· 6 6 import gleam/list 7 7 import gleam/option.{None, Some} 8 8 import gleeunit/should 9 - import lexicon_graphql/internal/lexicon/collection_meta as collection_meta 9 + import lexicon_graphql/internal/lexicon/collection_meta 10 10 import lexicon_graphql/query/dataloader 11 11 import lexicon_graphql/types 12 12 import swell/value
+9 -2
lexicon_graphql/test/field_type_validation_test.gleam
··· 92 92 93 93 pub fn property_to_field_type_blob_test() { 94 94 let property = 95 - types.Property(type_: "blob", required: True, format: option.None, ref: option.None) 95 + types.Property( 96 + type_: "blob", 97 + required: True, 98 + format: option.None, 99 + ref: option.None, 100 + ) 96 101 97 102 db_schema_builder.property_to_field_type(property) 98 103 |> should.equal(db_schema_builder.BlobField) ··· 339 344 340 345 db_schema_builder.validate_query_complexity(group_by) 341 346 |> should.be_error 342 - |> should.equal("Query too complex: maximum 5 group by fields allowed (got 6)") 347 + |> should.equal( 348 + "Query too complex: maximum 5 group by fields allowed (got 6)", 349 + ) 343 350 } 344 351 345 352 pub fn validate_query_complexity_empty_test() {
+1 -1
lexicon_graphql/test/nsid_test.gleam
··· 2 2 /// 3 3 /// NSIDs are used in AT Protocol to identify lexicons and collections 4 4 import gleeunit/should 5 - import lexicon_graphql/internal/lexicon/nsid as nsid 5 + import lexicon_graphql/internal/lexicon/nsid 6 6 7 7 pub fn nsid_to_type_name_test() { 8 8 nsid.to_type_name("xyz.statusphere.status")
+1 -1
lexicon_graphql/test/ref_resolver_test.gleam
··· 4 4 import gleam/dict 5 5 import gleam/option.{None, Some} 6 6 import gleeunit/should 7 - import lexicon_graphql/internal/lexicon/ref_resolver as ref_resolver 7 + import lexicon_graphql/internal/lexicon/ref_resolver 8 8 import lexicon_graphql/types 9 9 10 10 // Test resolving a local reference (within same lexicon)
+5 -2
lexicon_graphql/test/sorting_test.gleam
··· 12 12 import gleam/list 13 13 import gleam/option.{None, Some} 14 14 import gleeunit/should 15 - import lexicon_graphql/schema/database as db_schema_builder 16 15 import lexicon_graphql/schema/builder as schema_builder 16 + import lexicon_graphql/schema/database as db_schema_builder 17 17 import lexicon_graphql/types 18 18 import swell/introspection 19 19 import swell/schema ··· 29 29 } 30 30 31 31 // Mock aggregate fetcher for aggregation queries 32 - let aggregate_fetcher = fn(_collection: String, _params: db_schema_builder.AggregateParams) { 32 + let aggregate_fetcher = fn( 33 + _collection: String, 34 + _params: db_schema_builder.AggregateParams, 35 + ) { 33 36 Ok([]) 34 37 } 35 38
+10 -5
lexicon_graphql/test/subscription_schema_test.gleam
··· 54 54 None, 55 55 None, 56 56 None, 57 - None, // aggregate_fetcher 57 + None, 58 + // aggregate_fetcher 58 59 ) 59 60 { 60 61 Ok(s) -> { ··· 102 103 None, 103 104 None, 104 105 None, 105 - None, // aggregate_fetcher 106 + None, 107 + // aggregate_fetcher 106 108 ) 107 109 { 108 110 Ok(s) -> { ··· 172 174 None, 173 175 None, 174 176 None, 175 - None, // aggregate_fetcher 177 + None, 178 + // aggregate_fetcher 176 179 ) 177 180 { 178 181 Ok(s) -> { ··· 235 238 None, 236 239 None, 237 240 None, 238 - None, // aggregate_fetcher 241 + None, 242 + // aggregate_fetcher 239 243 ) 240 244 { 241 245 Ok(s) -> { ··· 320 324 None, 321 325 None, 322 326 None, 323 - None, // aggregate_fetcher 327 + None, 328 + // aggregate_fetcher 324 329 ) 325 330 { 326 331 Ok(s) -> {
+1 -1
lexicon_graphql/test/type_mapper_test.gleam
··· 2 2 /// 3 3 /// Maps AT Protocol lexicon types to GraphQL types 4 4 import gleeunit/should 5 - import lexicon_graphql/internal/graphql/type_mapper as type_mapper 5 + import lexicon_graphql/internal/graphql/type_mapper 6 6 import swell/schema 7 7 8 8 pub fn map_string_type_test() {
+1 -1
lexicon_graphql/test/uri_extractor_test.gleam
··· 4 4 import gleam/dict 5 5 import gleam/option.{None, Some} 6 6 import gleeunit/should 7 - import lexicon_graphql/internal/lexicon/uri_extractor as uri_extractor 7 + import lexicon_graphql/internal/lexicon/uri_extractor 8 8 import test_helpers 9 9 10 10 // Test extracting URI from a strongRef object
+4 -1
lexicon_graphql/test/where_schema_test.gleam
··· 29 29 } 30 30 31 31 // Mock aggregate fetcher for aggregation queries 32 - let aggregate_fetcher = fn(_collection: String, _params: db_schema_builder.AggregateParams) { 32 + let aggregate_fetcher = fn( 33 + _collection: String, 34 + _params: db_schema_builder.AggregateParams, 35 + ) { 33 36 Ok([]) 34 37 } 35 38
+1 -4
server/src/backfill.gleam
··· 675 675 } 676 676 677 677 /// Index records into the database using batch inserts 678 - pub fn index_records( 679 - records: List(Record), 680 - conn: sqlight.Connection, 681 - ) -> Nil { 678 + pub fn index_records(records: List(Record), conn: sqlight.Connection) -> Nil { 682 679 case records.batch_insert(conn, records) { 683 680 Ok(_) -> Nil 684 681 Error(err) -> {
+4 -10
server/src/client_schema.gleam
··· 5 5 import backfill 6 6 import database/repositories/actors 7 7 import database/repositories/config as config_repo 8 + import database/repositories/jetstream_activity 8 9 import database/repositories/lexicons 9 10 import database/repositories/records 10 - import database/repositories/jetstream_activity 11 11 import database/types.{type ActivityBucket, type ActivityEntry, type Lexicon} 12 12 import gleam/erlang/process 13 13 import gleam/list ··· 484 484 ]) 485 485 } 486 486 487 - fn activity_bucket_to_value( 488 - bucket: ActivityBucket, 489 - ) -> value.Value { 487 + fn activity_bucket_to_value(bucket: ActivityBucket) -> value.Value { 490 488 let total = bucket.create_count + bucket.update_count + bucket.delete_count 491 489 value.Object([ 492 490 #("timestamp", value.String(bucket.timestamp)), ··· 497 495 ]) 498 496 } 499 497 500 - fn activity_entry_to_value( 501 - entry: ActivityEntry, 502 - ) -> value.Value { 498 + fn activity_entry_to_value(entry: ActivityEntry) -> value.Value { 503 499 let error_msg_value = case entry.error_message { 504 500 Some(msg) -> value.String(msg) 505 501 None -> value.Null ··· 588 584 schema.non_null(settings_type()), 589 585 "Get system settings", 590 586 fn(_ctx) { 591 - let domain_authority = case 592 - config_repo.get(conn, "domain_authority") 593 - { 587 + let domain_authority = case config_repo.get(conn, "domain_authority") { 594 588 Ok(authority) -> authority 595 589 Error(_) -> "" 596 590 }
+1 -3
server/src/database/jetstream.gleam
··· 53 53 } 54 54 55 55 /// Clears the Jetstream cursor (for dev reset) 56 - pub fn clear_cursor( 57 - conn: sqlight.Connection, 58 - ) -> Result(Nil, sqlight.Error) { 56 + pub fn clear_cursor(conn: sqlight.Connection) -> Result(Nil, sqlight.Error) { 59 57 let sql = "DELETE FROM jetstream_cursor WHERE id = 1" 60 58 61 59 sqlight.exec(sql, conn)
+3 -1
server/src/database/repositories/jetstream_activity.gleam
··· 1 - import database/types.{type ActivityBucket, type ActivityEntry, ActivityBucket, ActivityEntry} 1 + import database/types.{ 2 + type ActivityBucket, type ActivityEntry, ActivityBucket, ActivityEntry, 3 + } 2 4 import gleam/dynamic/decode 3 5 import gleam/int 4 6 import gleam/option.{type Option, None, Some}
+1 -4
server/src/database/repositories/lexicons.gleam
··· 71 71 } 72 72 73 73 /// Checks if a lexicon exists by ID 74 - pub fn has( 75 - conn: sqlight.Connection, 76 - id: String, 77 - ) -> Result(Bool, sqlight.Error) { 74 + pub fn has(conn: sqlight.Connection, id: String) -> Result(Bool, sqlight.Error) { 78 75 let sql = 79 76 " 80 77 SELECT COUNT(*) as count
+1 -4
server/src/database/schema/migrations.gleam
··· 119 119 120 120 /// Migration v5: Add jetstream_cursor table for cursor tracking 121 121 fn migration_v5(conn: sqlight.Connection) -> Result(Nil, sqlight.Error) { 122 - logging.log( 123 - logging.Info, 124 - "Running migration v5 (jetstream_cursor table)...", 125 - ) 122 + logging.log(logging.Info, "Running migration v5 (jetstream_cursor table)...") 126 123 tables.create_jetstream_cursor_table(conn) 127 124 } 128 125
+1 -3
server/src/database/schema/tables.gleam
··· 121 121 } 122 122 123 123 /// Creates the CID index for record deduplication 124 - pub fn create_cid_index( 125 - conn: sqlight.Connection, 126 - ) -> Result(Nil, sqlight.Error) { 124 + pub fn create_cid_index(conn: sqlight.Connection) -> Result(Nil, sqlight.Error) { 127 125 let create_cid_index_sql = 128 126 " 129 127 CREATE INDEX IF NOT EXISTS idx_record_cid
+223 -216
server/src/event_handler.gleam
··· 1 1 import actor_validator 2 2 import backfill 3 3 import database/repositories/actors 4 + import database/repositories/jetstream_activity 4 5 import database/repositories/lexicons 5 6 import database/repositories/records 6 7 import database/types.{Inserted, Skipped} ··· 12 13 import gleam/result 13 14 import gleam/string 14 15 import goose 15 - import database/repositories/jetstream_activity 16 16 import honk 17 17 import honk/errors 18 18 import logging ··· 152 152 153 153 // Validate record against lexicon 154 154 case lexicon_jsons_result, record_json_result { 155 - Ok(lexicon_jsons), Ok(record_json) -> case 156 - honk.validate_record( 157 - lexicon_jsons, 158 - commit.collection, 159 - record_json, 160 - ) 161 - { 162 - Ok(_) -> { 163 - // Check if record already exists BEFORE inserting to determine operation type 164 - let existing_record = records.get(db, uri) 165 - let is_create = case existing_record { 166 - Ok([]) -> True 167 - // Empty list means record doesn't exist 168 - Ok(_) -> False 169 - // Non-empty list means record exists 170 - Error(_) -> { 171 - // Database error - log it and treat as update to be safe 172 - logging.log( 173 - logging.Warning, 174 - "[jetstream] Error checking existing record for " <> uri, 175 - ) 176 - False 177 - } 178 - } 179 - 180 - // Ensure actor exists before inserting record 181 - case actor_validator.ensure_actor_exists(db, did, plc_url) { 182 - Ok(is_new_actor) -> { 183 - // If this is a new actor, synchronously backfill all collections 184 - // This ensures subscription joins have complete data immediately 185 - // We're already in a spawned process per event, so blocking is fine 186 - case is_new_actor { 187 - True -> { 188 - // Publish stats event for new actor 189 - stats_pubsub.publish(stats_pubsub.ActorCreated) 190 - 191 - backfill.backfill_collections_for_actor( 192 - db, 193 - did, 194 - collection_ids, 195 - external_collection_ids, 196 - plc_url, 155 + Ok(lexicon_jsons), Ok(record_json) -> 156 + case 157 + honk.validate_record( 158 + lexicon_jsons, 159 + commit.collection, 160 + record_json, 161 + ) 162 + { 163 + Ok(_) -> { 164 + // Check if record already exists BEFORE inserting to determine operation type 165 + let existing_record = records.get(db, uri) 166 + let is_create = case existing_record { 167 + Ok([]) -> True 168 + // Empty list means record doesn't exist 169 + Ok(_) -> False 170 + // Non-empty list means record exists 171 + Error(_) -> { 172 + // Database error - log it and treat as update to be safe 173 + logging.log( 174 + logging.Warning, 175 + "[jetstream] Error checking existing record for " 176 + <> uri, 197 177 ) 178 + False 198 179 } 199 - False -> Nil 200 180 } 201 181 202 - // Continue with record insertion 203 - // Validation passed, insert record 182 + // Ensure actor exists before inserting record 204 183 case 205 - records.insert( 206 - db, 207 - uri, 208 - cid_value, 209 - did, 210 - commit.collection, 211 - json_string, 212 - ) 184 + actor_validator.ensure_actor_exists(db, did, plc_url) 213 185 { 214 - Ok(Inserted) -> { 215 - logging.log( 216 - logging.Info, 217 - "[jetstream] " 218 - <> case is_create { 219 - True -> "create" 220 - False -> "update" 186 + Ok(is_new_actor) -> { 187 + // If this is a new actor, synchronously backfill all collections 188 + // This ensures subscription joins have complete data immediately 189 + // We're already in a spawned process per event, so blocking is fine 190 + case is_new_actor { 191 + True -> { 192 + // Publish stats event for new actor 193 + stats_pubsub.publish(stats_pubsub.ActorCreated) 194 + 195 + backfill.backfill_collections_for_actor( 196 + db, 197 + did, 198 + collection_ids, 199 + external_collection_ids, 200 + plc_url, 201 + ) 221 202 } 222 - <> " " 223 - <> commit.collection 224 - <> " (" 225 - <> commit.rkey 226 - <> ") " 227 - <> did, 228 - ) 203 + False -> Nil 204 + } 229 205 230 - // Update activity status to success 231 - case activity_id { 232 - option.Some(id) -> { 233 - case 234 - jetstream_activity.update_status( 235 - db, 236 - id, 237 - "success", 238 - option.None, 239 - ) 240 - { 241 - Ok(_) -> 242 - // Publish activity event for real-time UI updates 243 - stats_pubsub.publish( 244 - stats_pubsub.ActivityLogged( 206 + // Continue with record insertion 207 + // Validation passed, insert record 208 + case 209 + records.insert( 210 + db, 211 + uri, 212 + cid_value, 213 + did, 214 + commit.collection, 215 + json_string, 216 + ) 217 + { 218 + Ok(Inserted) -> { 219 + logging.log( 220 + logging.Info, 221 + "[jetstream] " 222 + <> case is_create { 223 + True -> "create" 224 + False -> "update" 225 + } 226 + <> " " 227 + <> commit.collection 228 + <> " (" 229 + <> commit.rkey 230 + <> ") " 231 + <> did, 232 + ) 233 + 234 + // Update activity status to success 235 + case activity_id { 236 + option.Some(id) -> { 237 + case 238 + jetstream_activity.update_status( 239 + db, 245 240 id, 246 - timestamp, 247 - commit.operation, 248 - commit.collection, 249 - did, 250 241 "success", 251 242 option.None, 252 - event_json, 253 - ), 254 - ) 255 - Error(_) -> Nil 243 + ) 244 + { 245 + Ok(_) -> 246 + // Publish activity event for real-time UI updates 247 + stats_pubsub.publish( 248 + stats_pubsub.ActivityLogged( 249 + id, 250 + timestamp, 251 + commit.operation, 252 + commit.collection, 253 + did, 254 + "success", 255 + option.None, 256 + event_json, 257 + ), 258 + ) 259 + Error(_) -> Nil 260 + } 261 + } 262 + option.None -> Nil 256 263 } 257 - } 258 - option.None -> Nil 259 - } 260 264 261 - // Publish event to PubSub for GraphQL subscriptions 262 - let operation = case is_create { 263 - True -> pubsub.Create 264 - False -> pubsub.Update 265 - } 265 + // Publish event to PubSub for GraphQL subscriptions 266 + let operation = case is_create { 267 + True -> pubsub.Create 268 + False -> pubsub.Update 269 + } 266 270 267 - // Convert event timestamp from microseconds to ISO8601 268 - let indexed_at = microseconds_to_iso8601(time_us) 271 + // Convert event timestamp from microseconds to ISO8601 272 + let indexed_at = microseconds_to_iso8601(time_us) 269 273 270 - let event = 271 - pubsub.RecordEvent( 272 - uri: uri, 273 - cid: cid_value, 274 - did: did, 275 - collection: commit.collection, 276 - value: json_string, 277 - indexed_at: indexed_at, 278 - operation: operation, 279 - ) 274 + let event = 275 + pubsub.RecordEvent( 276 + uri: uri, 277 + cid: cid_value, 278 + did: did, 279 + collection: commit.collection, 280 + value: json_string, 281 + indexed_at: indexed_at, 282 + operation: operation, 283 + ) 280 284 281 - pubsub.publish(event) 285 + pubsub.publish(event) 282 286 283 - // Publish stats event for real-time stats updates 284 - case is_create { 285 - True -> 286 - stats_pubsub.publish(stats_pubsub.RecordCreated) 287 - False -> Nil 288 - } 289 - } 290 - Ok(Skipped) -> { 291 - logging.log( 292 - logging.Info, 293 - "[jetstream] skipped (duplicate CID) " 294 - <> commit.collection 295 - <> " (" 296 - <> commit.rkey 297 - <> ") " 298 - <> did, 299 - ) 300 - 301 - // Update activity status to success (but don't increment counters) 302 - case activity_id { 303 - option.Some(id) -> { 304 - case 305 - jetstream_activity.update_status( 306 - db, 307 - id, 308 - "success", 309 - option.Some("Skipped: duplicate CID"), 310 - ) 311 - { 312 - Ok(_) -> 313 - // Publish activity event for real-time UI updates 287 + // Publish stats event for real-time stats updates 288 + case is_create { 289 + True -> 314 290 stats_pubsub.publish( 315 - stats_pubsub.ActivityLogged( 291 + stats_pubsub.RecordCreated, 292 + ) 293 + False -> Nil 294 + } 295 + } 296 + Ok(Skipped) -> { 297 + logging.log( 298 + logging.Info, 299 + "[jetstream] skipped (duplicate CID) " 300 + <> commit.collection 301 + <> " (" 302 + <> commit.rkey 303 + <> ") " 304 + <> did, 305 + ) 306 + 307 + // Update activity status to success (but don't increment counters) 308 + case activity_id { 309 + option.Some(id) -> { 310 + case 311 + jetstream_activity.update_status( 312 + db, 316 313 id, 317 - timestamp, 318 - commit.operation, 319 - commit.collection, 320 - did, 321 314 "success", 322 315 option.Some("Skipped: duplicate CID"), 323 - event_json, 324 - ), 325 - ) 326 - Error(_) -> Nil 316 + ) 317 + { 318 + Ok(_) -> 319 + // Publish activity event for real-time UI updates 320 + stats_pubsub.publish( 321 + stats_pubsub.ActivityLogged( 322 + id, 323 + timestamp, 324 + commit.operation, 325 + commit.collection, 326 + did, 327 + "success", 328 + option.Some("Skipped: duplicate CID"), 329 + event_json, 330 + ), 331 + ) 332 + Error(_) -> Nil 333 + } 334 + } 335 + option.None -> Nil 336 + } 337 + // Don't publish RecordCreated event - record wasn't actually created 338 + } 339 + Error(err) -> { 340 + logging.log( 341 + logging.Error, 342 + "[jetstream] Failed to insert record " 343 + <> uri 344 + <> ": " 345 + <> string.inspect(err), 346 + ) 347 + 348 + // Update activity status to error 349 + case activity_id { 350 + option.Some(id) -> { 351 + case 352 + jetstream_activity.update_status( 353 + db, 354 + id, 355 + "error", 356 + option.Some( 357 + "Database insert failed: " 358 + <> string.inspect(err), 359 + ), 360 + ) 361 + { 362 + Ok(_) -> { 363 + let error_msg = 364 + "Database insert failed: " 365 + <> string.inspect(err) 366 + // Publish activity event for real-time UI updates 367 + stats_pubsub.publish( 368 + stats_pubsub.ActivityLogged( 369 + id, 370 + timestamp, 371 + commit.operation, 372 + commit.collection, 373 + did, 374 + "error", 375 + option.Some(error_msg), 376 + event_json, 377 + ), 378 + ) 379 + } 380 + Error(_) -> Nil 381 + } 382 + } 383 + option.None -> Nil 327 384 } 328 385 } 329 - option.None -> Nil 330 386 } 331 - // Don't publish RecordCreated event - record wasn't actually created 332 387 } 333 - Error(err) -> { 388 + Error(actor_err) -> { 334 389 logging.log( 335 390 logging.Error, 336 - "[jetstream] Failed to insert record " 391 + "[jetstream] Failed to validate/create actor for " 337 392 <> uri 338 393 <> ": " 339 - <> string.inspect(err), 394 + <> actor_err, 340 395 ) 341 396 342 397 // Update activity status to error ··· 348 403 id, 349 404 "error", 350 405 option.Some( 351 - "Database insert failed: " 352 - <> string.inspect(err), 406 + "Actor validation failed: " <> actor_err, 353 407 ), 354 408 ) 355 409 { 356 410 Ok(_) -> { 357 411 let error_msg = 358 - "Database insert failed: " 359 - <> string.inspect(err) 412 + "Actor validation failed: " <> actor_err 360 413 // Publish activity event for real-time UI updates 361 414 stats_pubsub.publish( 362 415 stats_pubsub.ActivityLogged( ··· 379 432 } 380 433 } 381 434 } 382 - Error(actor_err) -> { 435 + Error(validation_error) -> { 383 436 logging.log( 384 - logging.Error, 385 - "[jetstream] Failed to validate/create actor for " 437 + logging.Warning, 438 + "[jetstream] Validation failed for " 386 439 <> uri 387 440 <> ": " 388 - <> actor_err, 441 + <> errors.to_string(validation_error), 389 442 ) 390 443 391 - // Update activity status to error 444 + // Update activity status to validation_error 392 445 case activity_id { 393 446 option.Some(id) -> { 394 447 case 395 448 jetstream_activity.update_status( 396 449 db, 397 450 id, 398 - "error", 399 - option.Some( 400 - "Actor validation failed: " <> actor_err, 401 - ), 451 + "validation_error", 452 + option.Some(errors.to_string(validation_error)), 402 453 ) 403 454 { 404 455 Ok(_) -> { 405 - let error_msg = 406 - "Actor validation failed: " <> actor_err 456 + let error_msg = errors.to_string(validation_error) 407 457 // Publish activity event for real-time UI updates 408 458 stats_pubsub.publish(stats_pubsub.ActivityLogged( 409 459 id, ··· 411 461 commit.operation, 412 462 commit.collection, 413 463 did, 414 - "error", 464 + "validation_error", 415 465 option.Some(error_msg), 416 466 event_json, 417 467 )) ··· 423 473 } 424 474 } 425 475 } 426 - } 427 - Error(validation_error) -> { 428 - logging.log( 429 - logging.Warning, 430 - "[jetstream] Validation failed for " 431 - <> uri 432 - <> ": " 433 - <> errors.to_string(validation_error), 434 - ) 435 - 436 - // Update activity status to validation_error 437 - case activity_id { 438 - option.Some(id) -> { 439 - case 440 - jetstream_activity.update_status( 441 - db, 442 - id, 443 - "validation_error", 444 - option.Some(errors.to_string(validation_error)), 445 - ) 446 - { 447 - Ok(_) -> { 448 - let error_msg = 449 - errors.to_string(validation_error) 450 - // Publish activity event for real-time UI updates 451 - stats_pubsub.publish(stats_pubsub.ActivityLogged( 452 - id, 453 - timestamp, 454 - commit.operation, 455 - commit.collection, 456 - did, 457 - "validation_error", 458 - option.Some(error_msg), 459 - event_json, 460 - )) 461 - } 462 - Error(_) -> Nil 463 - } 464 - } 465 - option.None -> Nil 466 - } 467 - } 468 - } 469 476 Error(_lex_parse_err), _ | _, Error(_rec_parse_err) -> { 470 477 logging.log( 471 478 logging.Error,
+9 -14
server/src/jetstream_consumer.gleam
··· 166 166 } 167 167 168 168 /// Restart the Jetstream consumer with fresh lexicon data 169 - pub fn restart( 170 - manager: process.Subject(ManagerMessage), 171 - ) -> Result(Nil, String) { 169 + pub fn restart(manager: process.Subject(ManagerMessage)) -> Result(Nil, String) { 172 170 actor.call(manager, waiting: 5000, sending: ManualRestart) 173 171 } 174 172 ··· 265 263 CheckHeartbeat, 266 264 ) 267 265 268 - actor.continue(ManagerState( 269 - ..state, 270 - consumer_subject: option.None, 271 - )) 266 + actor.continue( 267 + ManagerState(..state, consumer_subject: option.None), 268 + ) 272 269 } 273 270 } 274 271 } ··· 463 460 // Flush the new cursor value (time_us) 464 461 case jetstream.set_cursor(state.db, time_us) { 465 462 Ok(_) -> { 466 - actor.continue( 467 - CursorState( 468 - db: state.db, 469 - last_flush_time: current_time, 470 - latest_cursor: option.None, 471 - ), 472 - ) 463 + actor.continue(CursorState( 464 + db: state.db, 465 + last_flush_time: current_time, 466 + latest_cursor: option.None, 467 + )) 473 468 } 474 469 Error(err) -> { 475 470 logging.log(
+3 -3
server/src/server.gleam
··· 2 2 import argv 3 3 import backfill 4 4 import backfill_state 5 - import handlers/backfill as backfill_handler 6 - import handlers/client_graphql as client_graphql_handler 7 5 import config 8 6 import database/connection 9 7 import database/repositories/lexicons ··· 16 14 import gleam/list 17 15 import gleam/option 18 16 import gleam/string 17 + import handlers/backfill as backfill_handler 18 + import handlers/client_graphql as client_graphql_handler 19 19 import handlers/graphiql as graphiql_handler 20 20 import handlers/graphql as graphql_handler 21 21 import handlers/graphql_ws as graphql_ws_handler 22 22 import handlers/health as health_handler 23 23 import handlers/index as index_handler 24 + import handlers/upload as upload_handler 24 25 import importer 25 26 import jetstream_consumer 26 27 import logging ··· 30 31 import pubsub 31 32 import sqlight 32 33 import stats_pubsub 33 - import handlers/upload as upload_handler 34 34 import wisp 35 35 import wisp/wisp_mist 36 36
+11 -4
server/src/where_clause.gleam
··· 124 124 /// Since sqlight.Value is opaque, we check the condition operators 125 125 fn should_cast_numeric(condition: WhereCondition) -> Bool { 126 126 // If any of the numeric comparison operators are present, we should cast 127 - option.is_some(condition.gt) || option.is_some(condition.gte) || 128 - option.is_some(condition.lt) || option.is_some(condition.lte) 127 + option.is_some(condition.gt) 128 + || option.is_some(condition.gte) 129 + || option.is_some(condition.lt) 130 + || option.is_some(condition.lte) 129 131 } 130 132 131 133 /// Builds field reference with optional numeric cast for JSON fields 132 - fn build_field_ref_with_cast(field: String, use_table_prefix: Bool, cast_numeric: Bool) -> String { 134 + fn build_field_ref_with_cast( 135 + field: String, 136 + use_table_prefix: Bool, 137 + cast_numeric: Bool, 138 + ) -> String { 133 139 let field_ref = build_field_ref(field, use_table_prefix) 134 140 135 141 // If it's a JSON field and we need numeric cast, wrap in CAST ··· 149 155 // Check if numeric casting is needed (for gt/gte/lt/lte operators) 150 156 let has_numeric_comparison = should_cast_numeric(condition) 151 157 152 - let field_ref = build_field_ref_with_cast(field, use_table_prefix, has_numeric_comparison) 158 + let field_ref = 159 + build_field_ref_with_cast(field, use_table_prefix, has_numeric_comparison) 153 160 let mut_sql_parts = [] 154 161 let mut_params = [] 155 162
+1 -3
server/src/where_converter.gleam
··· 19 19 } 20 20 21 21 /// Convert a where.WhereCondition to a where_clause.WhereCondition 22 - fn convert_condition( 23 - cond: where.WhereCondition, 24 - ) -> where_clause.WhereCondition { 22 + fn convert_condition(cond: where.WhereCondition) -> where_clause.WhereCondition { 25 23 where_clause.WhereCondition( 26 24 eq: option.map(cond.eq, convert_value), 27 25 in_values: option.map(cond.in_values, fn(values) {
+1 -1
server/test/database_sorting_test.gleam
··· 1 - import database/types 2 1 /// Database sorting integration tests 3 2 /// 4 3 /// Tests that SQL ORDER BY clauses are generated correctly and 5 4 /// that sorting works properly with the database 6 5 import database/repositories/records 7 6 import database/schema/tables 7 + import database/types 8 8 import gleam/list 9 9 import gleam/option.{None, Some} 10 10 import gleeunit/should
+2 -6
server/test/graphql_aggregation_integration_test.gleam
··· 1 1 import database/queries/aggregates 2 - import database/types 3 2 /// End-to-end integration tests for GraphQL aggregated queries 4 3 /// 5 4 /// Tests the complete aggregation flow: ··· 10 9 import database/repositories/lexicons 11 10 import database/repositories/records 12 11 import database/schema/tables 12 + import database/types 13 13 import gleam/dict 14 14 import gleam/http 15 15 import gleam/json ··· 108 108 109 109 // Insert post lexicon 110 110 let post_lexicon = create_post_lexicon() 111 - use _ <- result.try(lexicons.insert( 112 - conn, 113 - "app.bsky.feed.post", 114 - post_lexicon, 115 - )) 111 + use _ <- result.try(lexicons.insert(conn, "app.bsky.feed.post", post_lexicon)) 116 112 117 113 // Insert status lexicon 118 114 let status_lexicon = create_status_lexicon()
+10 -20
server/test/graphql_handler_integration_test.gleam
··· 114 114 115 115 // Insert a lexicon for xyz.statusphere.status 116 116 let lexicon = create_status_lexicon() 117 - let assert Ok(_) = 118 - lexicons.insert(db, "xyz.statusphere.status", lexicon) 117 + let assert Ok(_) = lexicons.insert(db, "xyz.statusphere.status", lexicon) 119 118 120 119 // Insert some test records 121 120 let record1_json = ··· 222 221 223 222 // Insert a lexicon but no records 224 223 let lexicon = create_simple_lexicon("xyz.statusphere.status") 225 - let assert Ok(_) = 226 - lexicons.insert(db, "xyz.statusphere.status", lexicon) 224 + let assert Ok(_) = lexicons.insert(db, "xyz.statusphere.status", lexicon) 227 225 228 226 // Create GraphQL query request with Connection structure 229 227 let query = ··· 273 271 274 272 // Insert a lexicon 275 273 let lexicon = create_simple_lexicon("xyz.statusphere.status") 276 - let assert Ok(_) = 277 - lexicons.insert(db, "xyz.statusphere.status", lexicon) 274 + let assert Ok(_) = lexicons.insert(db, "xyz.statusphere.status", lexicon) 278 275 279 276 // Create GraphQL GET request with query parameter 280 277 let request = ··· 449 446 ]) 450 447 |> json.to_string 451 448 452 - let assert Ok(_) = 453 - lexicons.insert(db, "xyz.statusphere.status", lexicon1) 449 + let assert Ok(_) = lexicons.insert(db, "xyz.statusphere.status", lexicon1) 454 450 let assert Ok(_) = lexicons.insert(db, "app.bsky.feed.post", lexicon2) 455 451 456 452 // Insert records for first collection ··· 562 558 563 559 // Insert a lexicon 564 560 let lexicon = create_simple_lexicon("xyz.statusphere.status") 565 - let assert Ok(_) = 566 - lexicons.insert(db, "xyz.statusphere.status", lexicon) 561 + let assert Ok(_) = lexicons.insert(db, "xyz.statusphere.status", lexicon) 567 562 568 563 // Insert 150 records (handler should limit to 100) 569 564 let _ = ··· 656 651 657 652 // Insert a lexicon for xyz.statusphere.status 658 653 let lexicon = create_status_lexicon() 659 - let assert Ok(_) = 660 - lexicons.insert(db, "xyz.statusphere.status", lexicon) 654 + let assert Ok(_) = lexicons.insert(db, "xyz.statusphere.status", lexicon) 661 655 662 656 // Insert test actors 663 - let assert Ok(_) = 664 - actors.upsert(db, "did:plc:alice", "alice.bsky.social") 657 + let assert Ok(_) = actors.upsert(db, "did:plc:alice", "alice.bsky.social") 665 658 let assert Ok(_) = actors.upsert(db, "did:plc:bob", "bob.bsky.social") 666 659 667 660 // Insert test records with those DIDs ··· 754 747 755 748 // Insert a lexicon for xyz.statusphere.status 756 749 let lexicon = create_status_lexicon() 757 - let assert Ok(_) = 758 - lexicons.insert(db, "xyz.statusphere.status", lexicon) 750 + let assert Ok(_) = lexicons.insert(db, "xyz.statusphere.status", lexicon) 759 751 760 752 // Insert test actors 761 - let assert Ok(_) = 762 - actors.upsert(db, "did:plc:alice", "alice.bsky.social") 753 + let assert Ok(_) = actors.upsert(db, "did:plc:alice", "alice.bsky.social") 763 754 let assert Ok(_) = actors.upsert(db, "did:plc:bob", "bob.bsky.social") 764 - let assert Ok(_) = 765 - actors.upsert(db, "did:plc:charlie", "charlie.bsky.social") 755 + let assert Ok(_) = actors.upsert(db, "did:plc:charlie", "charlie.bsky.social") 766 756 767 757 // Insert test records with those DIDs 768 758 let record1_json =
+2 -2
server/test/graphql_introspection_did_join_test.gleam
··· 13 13 import gleam/string 14 14 import gleeunit/should 15 15 import handlers/graphql as graphql_handler 16 - import importer 17 16 import honk 17 + import importer 18 18 import simplifile 19 19 import sqlight 20 20 import wisp ··· 41 41 let all_json_strings = list.map(file_contents, fn(pair) { pair.1 }) 42 42 use all_jsons <- result.try( 43 43 honk.parse_json_strings(all_json_strings) 44 - |> result.map_error(fn(_) { "Failed to parse JSON" }) 44 + |> result.map_error(fn(_) { "Failed to parse JSON" }), 45 45 ) 46 46 47 47 // Validate all schemas together (this allows cross-references to be resolved)
+5 -10
server/test/graphql_total_count_test.gleam
··· 93 93 94 94 // Insert a lexicon 95 95 let lexicon = create_status_lexicon() 96 - let assert Ok(_) = 97 - lexicons.insert(db, "xyz.statusphere.status", lexicon) 96 + let assert Ok(_) = lexicons.insert(db, "xyz.statusphere.status", lexicon) 98 97 99 98 // Insert 5 test records 100 99 let _ = ··· 172 171 173 172 // Insert a lexicon 174 173 let lexicon = create_status_lexicon() 175 - let assert Ok(_) = 176 - lexicons.insert(db, "xyz.statusphere.status", lexicon) 174 + let assert Ok(_) = lexicons.insert(db, "xyz.statusphere.status", lexicon) 177 175 178 176 // Insert test actors 179 - let assert Ok(_) = 180 - actors.upsert(db, "did:plc:alice", "alice.bsky.social") 177 + let assert Ok(_) = actors.upsert(db, "did:plc:alice", "alice.bsky.social") 181 178 let assert Ok(_) = actors.upsert(db, "did:plc:bob", "bob.bsky.social") 182 179 183 180 // Insert 3 records for alice ··· 286 283 287 284 // Insert a lexicon 288 285 let lexicon = create_status_lexicon() 289 - let assert Ok(_) = 290 - lexicons.insert(db, "xyz.statusphere.status", lexicon) 286 + let assert Ok(_) = lexicons.insert(db, "xyz.statusphere.status", lexicon) 291 287 292 288 // Query with totalCount field (no records inserted) 293 289 let query = ··· 336 332 337 333 // Insert a lexicon 338 334 let lexicon = create_status_lexicon() 339 - let assert Ok(_) = 340 - lexicons.insert(db, "xyz.statusphere.status", lexicon) 335 + let assert Ok(_) = lexicons.insert(db, "xyz.statusphere.status", lexicon) 341 336 342 337 // Insert 10 test records 343 338 let _ =
-1
server/test/groupby_enum_validation_test.gleam
··· 1 - 2 1 /// Integration test for groupBy field enum validation 3 2 /// 4 3 /// Verifies that aggregation queries use collection-specific GroupByField enums
+11 -22
server/test/join_integration_test.gleam
··· 167 167 168 168 // Insert lexicons 169 169 let post_lexicon = create_post_lexicon() 170 - let assert Ok(_) = 171 - lexicons.insert(db, "app.bsky.feed.post", post_lexicon) 170 + let assert Ok(_) = lexicons.insert(db, "app.bsky.feed.post", post_lexicon) 172 171 173 172 // Insert test records 174 173 // Parent post ··· 255 254 // Insert lexicons 256 255 let post_lexicon = create_post_lexicon() 257 256 let profile_lexicon = create_profile_lexicon() 258 - let assert Ok(_) = 259 - lexicons.insert(db, "app.bsky.feed.post", post_lexicon) 257 + let assert Ok(_) = lexicons.insert(db, "app.bsky.feed.post", post_lexicon) 260 258 let assert Ok(_) = 261 259 lexicons.insert(db, "app.bsky.actor.profile", profile_lexicon) 262 260 ··· 352 350 let post_lexicon = create_post_lexicon() 353 351 let like_lexicon = create_like_lexicon() 354 352 355 - let assert Ok(_) = 356 - lexicons.insert(db, "app.bsky.feed.post", post_lexicon) 353 + let assert Ok(_) = lexicons.insert(db, "app.bsky.feed.post", post_lexicon) 357 354 358 - let assert Ok(_) = 359 - lexicons.insert(db, "app.bsky.feed.like", like_lexicon) 355 + let assert Ok(_) = lexicons.insert(db, "app.bsky.feed.like", like_lexicon) 360 356 361 357 // Insert test records 362 358 // A post ··· 468 464 469 465 // Insert lexicons 470 466 let post_lexicon = create_post_lexicon() 471 - let assert Ok(_) = 472 - lexicons.insert(db, "app.bsky.feed.post", post_lexicon) 467 + let assert Ok(_) = lexicons.insert(db, "app.bsky.feed.post", post_lexicon) 473 468 474 469 // Insert multiple parent posts 475 470 let parent1_uri = "at://did:plc:user1/app.bsky.feed.post/parent1" ··· 594 589 // Insert lexicons 595 590 let post_lexicon = create_post_lexicon() 596 591 let profile_lexicon = create_profile_lexicon() 597 - let assert Ok(_) = 598 - lexicons.insert(db, "app.bsky.feed.post", post_lexicon) 592 + let assert Ok(_) = lexicons.insert(db, "app.bsky.feed.post", post_lexicon) 599 593 let assert Ok(_) = 600 594 lexicons.insert(db, "app.bsky.actor.profile", profile_lexicon) 601 595 ··· 720 714 // Insert lexicons 721 715 let post_lexicon = create_post_lexicon() 722 716 let like_lexicon = create_like_lexicon() 723 - let assert Ok(_) = 724 - lexicons.insert(db, "app.bsky.feed.post", post_lexicon) 725 - let assert Ok(_) = 726 - lexicons.insert(db, "app.bsky.feed.like", like_lexicon) 717 + let assert Ok(_) = lexicons.insert(db, "app.bsky.feed.post", post_lexicon) 718 + let assert Ok(_) = lexicons.insert(db, "app.bsky.feed.like", like_lexicon) 727 719 728 720 // Insert a parent post 729 721 let parent_post_uri = "at://did:plc:parent/app.bsky.feed.post/parent1" ··· 912 904 // Insert lexicons 913 905 let post_lexicon = create_post_lexicon() 914 906 let profile_lexicon = create_profile_lexicon_with_literal_self() 915 - let assert Ok(_) = 916 - lexicons.insert(db, "app.bsky.feed.post", post_lexicon) 907 + let assert Ok(_) = lexicons.insert(db, "app.bsky.feed.post", post_lexicon) 917 908 let assert Ok(_) = 918 909 lexicons.insert(db, "app.bsky.actor.profile", profile_lexicon) 919 910 ··· 1010 1001 // Insert lexicons 1011 1002 let post_lexicon = create_post_lexicon() 1012 1003 let profile_lexicon = create_profile_lexicon_with_literal_self() 1013 - let assert Ok(_) = 1014 - lexicons.insert(db, "app.bsky.feed.post", post_lexicon) 1004 + let assert Ok(_) = lexicons.insert(db, "app.bsky.feed.post", post_lexicon) 1015 1005 let assert Ok(_) = 1016 1006 lexicons.insert(db, "app.bsky.actor.profile", profile_lexicon) 1017 1007 ··· 1129 1119 // Insert lexicons 1130 1120 let post_lexicon = create_post_lexicon() 1131 1121 let profile_lexicon = create_profile_lexicon_with_literal_self() 1132 - let assert Ok(_) = 1133 - lexicons.insert(db, "app.bsky.feed.post", post_lexicon) 1122 + let assert Ok(_) = lexicons.insert(db, "app.bsky.feed.post", post_lexicon) 1134 1123 let assert Ok(_) = 1135 1124 lexicons.insert(db, "app.bsky.actor.profile", profile_lexicon) 1136 1125
+1 -2
server/test/nested_join_sortby_where_test.gleam
··· 656 656 profile1_json, 657 657 ) 658 658 659 - let assert Ok(_) = 660 - actors.upsert(db, "did:plc:user1", "chadtmiller.com") 659 + let assert Ok(_) = actors.upsert(db, "did:plc:user1", "chadtmiller.com") 661 660 662 661 let profile2_uri = "at://did:plc:user2/app.bsky.actor.profile/self" 663 662 let profile2_json =
+5 -10
server/test/paginated_join_test.gleam
··· 156 156 // Insert lexicons 157 157 let post_lexicon = create_post_lexicon() 158 158 let profile_lexicon = create_profile_lexicon() 159 - let assert Ok(_) = 160 - lexicons.insert(db, "app.bsky.feed.post", post_lexicon) 159 + let assert Ok(_) = lexicons.insert(db, "app.bsky.feed.post", post_lexicon) 161 160 let assert Ok(_) = 162 161 lexicons.insert(db, "app.bsky.actor.profile", profile_lexicon) 163 162 ··· 273 272 // Insert lexicons 274 273 let post_lexicon = create_post_lexicon() 275 274 let profile_lexicon = create_profile_lexicon() 276 - let assert Ok(_) = 277 - lexicons.insert(db, "app.bsky.feed.post", post_lexicon) 275 + let assert Ok(_) = lexicons.insert(db, "app.bsky.feed.post", post_lexicon) 278 276 let assert Ok(_) = 279 277 lexicons.insert(db, "app.bsky.actor.profile", profile_lexicon) 280 278 ··· 386 384 // Insert lexicons 387 385 let post_lexicon = create_post_lexicon() 388 386 let like_lexicon = create_like_lexicon() 389 - let assert Ok(_) = 390 - lexicons.insert(db, "app.bsky.feed.post", post_lexicon) 391 - let assert Ok(_) = 392 - lexicons.insert(db, "app.bsky.feed.like", like_lexicon) 387 + let assert Ok(_) = lexicons.insert(db, "app.bsky.feed.post", post_lexicon) 388 + let assert Ok(_) = lexicons.insert(db, "app.bsky.feed.like", like_lexicon) 393 389 394 390 // Insert a post 395 391 let post_uri = "at://did:plc:author/app.bsky.feed.post/post1" ··· 505 501 // Insert lexicons 506 502 let post_lexicon = create_post_lexicon() 507 503 let profile_lexicon = create_profile_lexicon() 508 - let assert Ok(_) = 509 - lexicons.insert(db, "app.bsky.feed.post", post_lexicon) 504 + let assert Ok(_) = lexicons.insert(db, "app.bsky.feed.post", post_lexicon) 510 505 let assert Ok(_) = 511 506 lexicons.insert(db, "app.bsky.actor.profile", profile_lexicon) 512 507
+2 -10
server/test/reverse_join_field_resolution_test.gleam
··· 246 246 247 247 // Insert lexicons 248 248 let assert Ok(_) = 249 - lexicons.insert( 250 - conn, 251 - "social.grain.gallery", 252 - create_gallery_lexicon(), 253 - ) 249 + lexicons.insert(conn, "social.grain.gallery", create_gallery_lexicon()) 254 250 let assert Ok(_) = 255 251 lexicons.insert( 256 252 conn, ··· 460 456 create_profile_lexicon(), 461 457 ) 462 458 let assert Ok(_) = 463 - lexicons.insert( 464 - conn, 465 - "social.grain.gallery", 466 - create_gallery_lexicon(), 467 - ) 459 + lexicons.insert(conn, "social.grain.gallery", create_gallery_lexicon()) 468 460 let assert Ok(_) = 469 461 lexicons.insert( 470 462 conn,
+2 -2
server/test/sorting_enum_validation_test.gleam
··· 1 - 2 1 /// Integration test for sorting enum validation 3 2 /// 4 3 /// Verifies that each Connection field uses the correct collection-specific ··· 392 391 }" 393 392 394 393 [ 395 - lexicon_graphql.parse_lexicon(gallery_json) |> result.unwrap(empty_lexicon()), 394 + lexicon_graphql.parse_lexicon(gallery_json) 395 + |> result.unwrap(empty_lexicon()), 396 396 lexicon_graphql.parse_lexicon(gallery_item_json) 397 397 |> result.unwrap(empty_lexicon()), 398 398 lexicon_graphql.parse_lexicon(favorite_json)
+4 -1
server/test/where_sql_builder_test.gleam
··· 385 385 386 386 // Should have both table column and JSON extract with CAST for numeric comparison 387 387 should.be_true(string.contains(sql, "collection = ?")) 388 - should.be_true(string.contains(sql, "CAST(json_extract(json, '$.replyCount') AS INTEGER) > ?")) 388 + should.be_true(string.contains( 389 + sql, 390 + "CAST(json_extract(json, '$.replyCount') AS INTEGER) > ?", 391 + )) 389 392 should.be_true(string.contains(sql, "AND")) 390 393 list.length(params) |> should.equal(2) 391 394 }