@@ -13,154 +13,154 @@ type DbTransactionCallback<A> = Parameters<typeof Database.transaction<A>>[0]
1313
1414const ACCOUNT_STATE_ID = 1
1515
16- export namespace AccountRepo {
17- export interface Service {
18- readonly active : ( ) => Effect . Effect < Option . Option < Info > , AccountRepoError >
19- readonly list : ( ) => Effect . Effect < Info [ ] , AccountRepoError >
20- readonly remove : ( accountID : AccountID ) => Effect . Effect < void , AccountRepoError >
21- readonly use : ( accountID : AccountID , orgID : Option . Option < OrgID > ) => Effect . Effect < void , AccountRepoError >
22- readonly getRow : ( accountID : AccountID ) => Effect . Effect < Option . Option < AccountRow > , AccountRepoError >
23- readonly persistToken : ( input : {
24- accountID : AccountID
25- accessToken : AccessToken
26- refreshToken : RefreshToken
27- expiry : Option . Option < number >
28- } ) => Effect . Effect < void , AccountRepoError >
29- readonly persistAccount : ( input : {
30- id : AccountID
31- email : string
32- url : string
33- accessToken : AccessToken
34- refreshToken : RefreshToken
35- expiry : number
36- orgID : Option . Option < OrgID >
37- } ) => Effect . Effect < void , AccountRepoError >
38- }
16+ export interface Interface {
17+ readonly active : ( ) => Effect . Effect < Option . Option < Info > , AccountRepoError >
18+ readonly list : ( ) => Effect . Effect < Info [ ] , AccountRepoError >
19+ readonly remove : ( accountID : AccountID ) => Effect . Effect < void , AccountRepoError >
20+ readonly use : ( accountID : AccountID , orgID : Option . Option < OrgID > ) => Effect . Effect < void , AccountRepoError >
21+ readonly getRow : ( accountID : AccountID ) => Effect . Effect < Option . Option < AccountRow > , AccountRepoError >
22+ readonly persistToken : ( input : {
23+ accountID : AccountID
24+ accessToken : AccessToken
25+ refreshToken : RefreshToken
26+ expiry : Option . Option < number >
27+ } ) => Effect . Effect < void , AccountRepoError >
28+ readonly persistAccount : ( input : {
29+ id : AccountID
30+ email : string
31+ url : string
32+ accessToken : AccessToken
33+ refreshToken : RefreshToken
34+ expiry : number
35+ orgID : Option . Option < OrgID >
36+ } ) => Effect . Effect < void , AccountRepoError >
3937}
4038
41- export class AccountRepo extends Context . Service < AccountRepo , AccountRepo . Service > ( ) ( "@opencode/AccountRepo" ) {
42- static readonly layer : Layer . Layer < AccountRepo > = Layer . effect (
43- AccountRepo ,
44- Effect . gen ( function * ( ) {
45- const decode = Schema . decodeUnknownSync ( Info )
39+ export class Service extends Context . Service < Service , Interface > ( ) ( "@opencode/AccountRepo" ) { }
4640
47- const query = < A > ( f : DbTransactionCallback < A > ) =>
48- Effect . try ( {
49- try : ( ) => Database . use ( f ) ,
50- catch : ( cause ) => new AccountRepoError ( { message : "Database operation failed" , cause } ) ,
51- } )
41+ export const layer : Layer . Layer < Service > = Layer . effect (
42+ Service ,
43+ Effect . gen ( function * ( ) {
44+ const decode = Schema . decodeUnknownSync ( Info )
5245
53- const tx = < A > ( f : DbTransactionCallback < A > ) =>
54- Effect . try ( {
55- try : ( ) => Database . transaction ( f ) ,
56- catch : ( cause ) => new AccountRepoError ( { message : "Database operation failed" , cause } ) ,
57- } )
46+ const query = < A > ( f : DbTransactionCallback < A > ) =>
47+ Effect . try ( {
48+ try : ( ) => Database . use ( f ) ,
49+ catch : ( cause ) => new AccountRepoError ( { message : "Database operation failed" , cause } ) ,
50+ } )
5851
59- const current = ( db : DbClient ) => {
60- const state = db . select ( ) . from ( AccountStateTable ) . where ( eq ( AccountStateTable . id , ACCOUNT_STATE_ID ) ) . get ( )
61- if ( ! state ?. active_account_id ) return
62- const account = db . select ( ) . from ( AccountTable ) . where ( eq ( AccountTable . id , state . active_account_id ) ) . get ( )
63- if ( ! account ) return
64- return { ...account , active_org_id : state . active_org_id ?? null }
65- }
66-
67- const state = ( db : DbClient , accountID : AccountID , orgID : Option . Option < OrgID > ) => {
68- const id = Option . getOrNull ( orgID )
69- return db
70- . insert ( AccountStateTable )
71- . values ( { id : ACCOUNT_STATE_ID , active_account_id : accountID , active_org_id : id } )
72- . onConflictDoUpdate ( {
73- target : AccountStateTable . id ,
74- set : { active_account_id : accountID , active_org_id : id } ,
75- } )
52+ const tx = < A > ( f : DbTransactionCallback < A > ) =>
53+ Effect . try ( {
54+ try : ( ) => Database . transaction ( f ) ,
55+ catch : ( cause ) => new AccountRepoError ( { message : "Database operation failed" , cause } ) ,
56+ } )
57+
58+ const current = ( db : DbClient ) => {
59+ const state = db . select ( ) . from ( AccountStateTable ) . where ( eq ( AccountStateTable . id , ACCOUNT_STATE_ID ) ) . get ( )
60+ if ( ! state ?. active_account_id ) return
61+ const account = db . select ( ) . from ( AccountTable ) . where ( eq ( AccountTable . id , state . active_account_id ) ) . get ( )
62+ if ( ! account ) return
63+ return { ...account , active_org_id : state . active_org_id ?? null }
64+ }
65+
66+ const state = ( db : DbClient , accountID : AccountID , orgID : Option . Option < OrgID > ) => {
67+ const id = Option . getOrNull ( orgID )
68+ return db
69+ . insert ( AccountStateTable )
70+ . values ( { id : ACCOUNT_STATE_ID , active_account_id : accountID , active_org_id : id } )
71+ . onConflictDoUpdate ( {
72+ target : AccountStateTable . id ,
73+ set : { active_account_id : accountID , active_org_id : id } ,
74+ } )
75+ . run ( )
76+ }
77+
78+ const active = Effect . fn ( "AccountRepo.active" ) ( ( ) =>
79+ query ( ( db ) => current ( db ) ) . pipe ( Effect . map ( ( row ) => ( row ? Option . some ( decode ( row ) ) : Option . none ( ) ) ) ) ,
80+ )
81+
82+ const list = Effect . fn ( "AccountRepo.list" ) ( ( ) =>
83+ query ( ( db ) =>
84+ db
85+ . select ( )
86+ . from ( AccountTable )
87+ . all ( )
88+ . map ( ( row : AccountRow ) => decode ( { ...row , active_org_id : null } ) ) ,
89+ ) ,
90+ )
91+
92+ const remove = Effect . fn ( "AccountRepo.remove" ) ( ( accountID : AccountID ) =>
93+ tx ( ( db ) => {
94+ db . update ( AccountStateTable )
95+ . set ( { active_account_id : null , active_org_id : null } )
96+ . where ( eq ( AccountStateTable . active_account_id , accountID ) )
7697 . run ( )
77- }
78-
79- const active = Effect . fn ( "AccountRepo.active" ) ( ( ) =>
80- query ( ( db ) => current ( db ) ) . pipe ( Effect . map ( ( row ) => ( row ? Option . some ( decode ( row ) ) : Option . none ( ) ) ) ) ,
81- )
82-
83- const list = Effect . fn ( "AccountRepo.list" ) ( ( ) =>
84- query ( ( db ) =>
85- db
86- . select ( )
87- . from ( AccountTable )
88- . all ( )
89- . map ( ( row : AccountRow ) => decode ( { ...row , active_org_id : null } ) ) ,
90- ) ,
91- )
92-
93- const remove = Effect . fn ( "AccountRepo.remove" ) ( ( accountID : AccountID ) =>
94- tx ( ( db ) => {
95- db . update ( AccountStateTable )
96- . set ( { active_account_id : null , active_org_id : null } )
97- . where ( eq ( AccountStateTable . active_account_id , accountID ) )
98- . run ( )
99- db . delete ( AccountTable ) . where ( eq ( AccountTable . id , accountID ) ) . run ( )
100- } ) . pipe ( Effect . asVoid ) ,
101- )
102-
103- const use = Effect . fn ( "AccountRepo.use" ) ( ( accountID : AccountID , orgID : Option . Option < OrgID > ) =>
104- query ( ( db ) => state ( db , accountID , orgID ) ) . pipe ( Effect . asVoid ) ,
105- )
106-
107- const getRow = Effect . fn ( "AccountRepo.getRow" ) ( ( accountID : AccountID ) =>
108- query ( ( db ) => db . select ( ) . from ( AccountTable ) . where ( eq ( AccountTable . id , accountID ) ) . get ( ) ) . pipe (
109- Effect . map ( Option . fromNullishOr ) ,
110- ) ,
111- )
112-
113- const persistToken = Effect . fn ( "AccountRepo.persistToken" ) ( ( input ) =>
114- query ( ( db ) =>
115- db
116- . update ( AccountTable )
117- . set ( {
118- access_token : input . accessToken ,
119- refresh_token : input . refreshToken ,
120- token_expiry : Option . getOrNull ( input . expiry ) ,
121- } )
122- . where ( eq ( AccountTable . id , input . accountID ) )
123- . run ( ) ,
124- ) . pipe ( Effect . asVoid ) ,
125- )
126-
127- const persistAccount = Effect . fn ( "AccountRepo.persistAccount" ) ( ( input ) =>
128- tx ( ( db ) => {
129- const url = normalizeServerUrl ( input . url )
130-
131- db . insert ( AccountTable )
132- . values ( {
133- id : input . id ,
98+ db . delete ( AccountTable ) . where ( eq ( AccountTable . id , accountID ) ) . run ( )
99+ } ) . pipe ( Effect . asVoid ) ,
100+ )
101+
102+ const use = Effect . fn ( "AccountRepo.use" ) ( ( accountID : AccountID , orgID : Option . Option < OrgID > ) =>
103+ query ( ( db ) => state ( db , accountID , orgID ) ) . pipe ( Effect . asVoid ) ,
104+ )
105+
106+ const getRow = Effect . fn ( "AccountRepo.getRow" ) ( ( accountID : AccountID ) =>
107+ query ( ( db ) => db . select ( ) . from ( AccountTable ) . where ( eq ( AccountTable . id , accountID ) ) . get ( ) ) . pipe (
108+ Effect . map ( Option . fromNullishOr ) ,
109+ ) ,
110+ )
111+
112+ const persistToken = Effect . fn ( "AccountRepo.persistToken" ) ( ( input ) =>
113+ query ( ( db ) =>
114+ db
115+ . update ( AccountTable )
116+ . set ( {
117+ access_token : input . accessToken ,
118+ refresh_token : input . refreshToken ,
119+ token_expiry : Option . getOrNull ( input . expiry ) ,
120+ } )
121+ . where ( eq ( AccountTable . id , input . accountID ) )
122+ . run ( ) ,
123+ ) . pipe ( Effect . asVoid ) ,
124+ )
125+
126+ const persistAccount = Effect . fn ( "AccountRepo.persistAccount" ) ( ( input ) =>
127+ tx ( ( db ) => {
128+ const url = normalizeServerUrl ( input . url )
129+
130+ db . insert ( AccountTable )
131+ . values ( {
132+ id : input . id ,
133+ email : input . email ,
134+ url,
135+ access_token : input . accessToken ,
136+ refresh_token : input . refreshToken ,
137+ token_expiry : input . expiry ,
138+ } )
139+ . onConflictDoUpdate ( {
140+ target : AccountTable . id ,
141+ set : {
134142 email : input . email ,
135143 url,
136144 access_token : input . accessToken ,
137145 refresh_token : input . refreshToken ,
138146 token_expiry : input . expiry ,
139- } )
140- . onConflictDoUpdate ( {
141- target : AccountTable . id ,
142- set : {
143- email : input . email ,
144- url,
145- access_token : input . accessToken ,
146- refresh_token : input . refreshToken ,
147- token_expiry : input . expiry ,
148- } ,
149- } )
150- . run ( )
151- void state ( db , input . id , input . orgID )
152- } ) . pipe ( Effect . asVoid ) ,
153- )
154-
155- return AccountRepo . of ( {
156- active,
157- list,
158- remove,
159- use,
160- getRow,
161- persistToken,
162- persistAccount,
163- } )
164- } ) ,
165- )
166- }
147+ } ,
148+ } )
149+ . run ( )
150+ void state ( db , input . id , input . orgID )
151+ } ) . pipe ( Effect . asVoid ) ,
152+ )
153+
154+ return Service . of ( {
155+ active,
156+ list,
157+ remove,
158+ use,
159+ getRow,
160+ persistToken,
161+ persistAccount,
162+ } )
163+ } ) ,
164+ )
165+
166+ export * as AccountRepo from "./repo"
0 commit comments