+40
.sqlx/query-09d75b756a6bd981cf2a9e922eccc38677bee474813c66465904aec3c0da1c3e.json
+40
.sqlx/query-09d75b756a6bd981cf2a9e922eccc38677bee474813c66465904aec3c0da1c3e.json
···
···
1
+
{
2
+
"db_name": "PostgreSQL",
3
+
"query": "\n SELECT u.handle, u.did, u.email, k.key_bytes\n FROM sessions s\n JOIN users u ON s.did = u.did\n JOIN user_keys k ON u.id = k.user_id\n WHERE s.access_jwt = $1\n ",
4
+
"describe": {
5
+
"columns": [
6
+
{
7
+
"ordinal": 0,
8
+
"name": "handle",
9
+
"type_info": "Text"
10
+
},
11
+
{
12
+
"ordinal": 1,
13
+
"name": "did",
14
+
"type_info": "Text"
15
+
},
16
+
{
17
+
"ordinal": 2,
18
+
"name": "email",
19
+
"type_info": "Text"
20
+
},
21
+
{
22
+
"ordinal": 3,
23
+
"name": "key_bytes",
24
+
"type_info": "Bytea"
25
+
}
26
+
],
27
+
"parameters": {
28
+
"Left": [
29
+
"Text"
30
+
]
31
+
},
32
+
"nullable": [
33
+
false,
34
+
false,
35
+
false,
36
+
false
37
+
]
38
+
},
39
+
"hash": "09d75b756a6bd981cf2a9e922eccc38677bee474813c66465904aec3c0da1c3e"
40
+
}
+18
.sqlx/query-0f10bde03edc0233a332e210a84a4186977c71efd3be80e2508a60ea5802cb1b.json
+18
.sqlx/query-0f10bde03edc0233a332e210a84a4186977c71efd3be80e2508a60ea5802cb1b.json
···
···
1
+
{
2
+
"db_name": "PostgreSQL",
3
+
"query": "INSERT INTO blobs (cid, mime_type, size_bytes, created_by_user, storage_key) VALUES ($1, $2, $3, $4, $5) ON CONFLICT (cid) DO NOTHING",
4
+
"describe": {
5
+
"columns": [],
6
+
"parameters": {
7
+
"Left": [
8
+
"Text",
9
+
"Text",
10
+
"Int8",
11
+
"Uuid",
12
+
"Text"
13
+
]
14
+
},
15
+
"nullable": []
16
+
},
17
+
"hash": "0f10bde03edc0233a332e210a84a4186977c71efd3be80e2508a60ea5802cb1b"
18
+
}
+29
.sqlx/query-0f8fd9cbb1ff0fd8951ce082a82cc058ec6db0dde3ab0059d6f340a1fd9ddade.json
+29
.sqlx/query-0f8fd9cbb1ff0fd8951ce082a82cc058ec6db0dde3ab0059d6f340a1fd9ddade.json
···
···
1
+
{
2
+
"db_name": "PostgreSQL",
3
+
"query": "\n SELECT u.did, r.repo_root_cid\n FROM repos r\n JOIN users u ON r.user_id = u.id\n WHERE u.did > $1\n ORDER BY u.did ASC\n LIMIT $2\n ",
4
+
"describe": {
5
+
"columns": [
6
+
{
7
+
"ordinal": 0,
8
+
"name": "did",
9
+
"type_info": "Text"
10
+
},
11
+
{
12
+
"ordinal": 1,
13
+
"name": "repo_root_cid",
14
+
"type_info": "Text"
15
+
}
16
+
],
17
+
"parameters": {
18
+
"Left": [
19
+
"Text",
20
+
"Int8"
21
+
]
22
+
},
23
+
"nullable": [
24
+
false,
25
+
false
26
+
]
27
+
},
28
+
"hash": "0f8fd9cbb1ff0fd8951ce082a82cc058ec6db0dde3ab0059d6f340a1fd9ddade"
29
+
}
+25
.sqlx/query-0fdf13907693d130babae38f4bb1df772dc11ab682f47918cacb5ae186b4eb24.json
+25
.sqlx/query-0fdf13907693d130babae38f4bb1df772dc11ab682f47918cacb5ae186b4eb24.json
···
···
1
+
{
2
+
"db_name": "PostgreSQL",
3
+
"query": "\n SELECT cid FROM blobs\n WHERE created_by_user = $1 AND cid > $2 AND created_at > $3\n ORDER BY cid ASC\n LIMIT $4\n ",
4
+
"describe": {
5
+
"columns": [
6
+
{
7
+
"ordinal": 0,
8
+
"name": "cid",
9
+
"type_info": "Text"
10
+
}
11
+
],
12
+
"parameters": {
13
+
"Left": [
14
+
"Uuid",
15
+
"Text",
16
+
"Timestamptz",
17
+
"Int8"
18
+
]
19
+
},
20
+
"nullable": [
21
+
false
22
+
]
23
+
},
24
+
"hash": "0fdf13907693d130babae38f4bb1df772dc11ab682f47918cacb5ae186b4eb24"
25
+
}
+15
.sqlx/query-14a68a119586aa980fb7b64646c1373eecd788e508246b5ad84e31b1adbdd2c1.json
+15
.sqlx/query-14a68a119586aa980fb7b64646c1373eecd788e508246b5ad84e31b1adbdd2c1.json
···
···
1
+
{
2
+
"db_name": "PostgreSQL",
3
+
"query": "INSERT INTO repos (user_id, repo_root_cid) VALUES ($1, $2)",
4
+
"describe": {
5
+
"columns": [],
6
+
"parameters": {
7
+
"Left": [
8
+
"Uuid",
9
+
"Text"
10
+
]
11
+
},
12
+
"nullable": []
13
+
},
14
+
"hash": "14a68a119586aa980fb7b64646c1373eecd788e508246b5ad84e31b1adbdd2c1"
15
+
}
+18
.sqlx/query-15a3cb31c36192c76c0cfa881043d70a1cc2c212fa382f8d9efc3c35ea4e66c1.json
+18
.sqlx/query-15a3cb31c36192c76c0cfa881043d70a1cc2c212fa382f8d9efc3c35ea4e66c1.json
···
···
1
+
{
2
+
"db_name": "PostgreSQL",
3
+
"query": "INSERT INTO app_passwords (user_id, name, password_hash, created_at, privileged) VALUES ($1, $2, $3, $4, $5)",
4
+
"describe": {
5
+
"columns": [],
6
+
"parameters": {
7
+
"Left": [
8
+
"Uuid",
9
+
"Text",
10
+
"Text",
11
+
"Timestamptz",
12
+
"Bool"
13
+
]
14
+
},
15
+
"nullable": []
16
+
},
17
+
"hash": "15a3cb31c36192c76c0cfa881043d70a1cc2c212fa382f8d9efc3c35ea4e66c1"
18
+
}
+40
.sqlx/query-176d30f31356a4d128764c9c2eece81f8079a29e40b07ba58adc4380d58068c8.json
+40
.sqlx/query-176d30f31356a4d128764c9c2eece81f8079a29e40b07ba58adc4380d58068c8.json
···
···
1
+
{
2
+
"db_name": "PostgreSQL",
3
+
"query": "\n SELECT did, handle, email, created_at\n FROM users\n WHERE did = $1\n ",
4
+
"describe": {
5
+
"columns": [
6
+
{
7
+
"ordinal": 0,
8
+
"name": "did",
9
+
"type_info": "Text"
10
+
},
11
+
{
12
+
"ordinal": 1,
13
+
"name": "handle",
14
+
"type_info": "Text"
15
+
},
16
+
{
17
+
"ordinal": 2,
18
+
"name": "email",
19
+
"type_info": "Text"
20
+
},
21
+
{
22
+
"ordinal": 3,
23
+
"name": "created_at",
24
+
"type_info": "Timestamptz"
25
+
}
26
+
],
27
+
"parameters": {
28
+
"Left": [
29
+
"Text"
30
+
]
31
+
},
32
+
"nullable": [
33
+
false,
34
+
false,
35
+
false,
36
+
false
37
+
]
38
+
},
39
+
"hash": "176d30f31356a4d128764c9c2eece81f8079a29e40b07ba58adc4380d58068c8"
40
+
}
+28
.sqlx/query-1d3748694f23a407e26c793cc43e91c4fa9753dc7c7fd964f6c43de27c5bac4a.json
+28
.sqlx/query-1d3748694f23a407e26c793cc43e91c4fa9753dc7c7fd964f6c43de27c5bac4a.json
···
···
1
+
{
2
+
"db_name": "PostgreSQL",
3
+
"query": "\n SELECT u.did, r.repo_root_cid\n FROM users u\n LEFT JOIN repos r ON u.id = r.user_id\n WHERE u.did = $1\n ",
4
+
"describe": {
5
+
"columns": [
6
+
{
7
+
"ordinal": 0,
8
+
"name": "did",
9
+
"type_info": "Text"
10
+
},
11
+
{
12
+
"ordinal": 1,
13
+
"name": "repo_root_cid",
14
+
"type_info": "Text"
15
+
}
16
+
],
17
+
"parameters": {
18
+
"Left": [
19
+
"Text"
20
+
]
21
+
},
22
+
"nullable": [
23
+
false,
24
+
false
25
+
]
26
+
},
27
+
"hash": "1d3748694f23a407e26c793cc43e91c4fa9753dc7c7fd964f6c43de27c5bac4a"
28
+
}
+14
.sqlx/query-1ee6eda3e44660e7f14fcfe56adc2d41c72901b9c701fc7b992314e5370b32dc.json
+14
.sqlx/query-1ee6eda3e44660e7f14fcfe56adc2d41c72901b9c701fc7b992314e5370b32dc.json
···
···
1
+
{
2
+
"db_name": "PostgreSQL",
3
+
"query": "UPDATE invite_codes SET available_uses = available_uses - 1 WHERE code = $1",
4
+
"describe": {
5
+
"columns": [],
6
+
"parameters": {
7
+
"Left": [
8
+
"Text"
9
+
]
10
+
},
11
+
"nullable": []
12
+
},
13
+
"hash": "1ee6eda3e44660e7f14fcfe56adc2d41c72901b9c701fc7b992314e5370b32dc"
14
+
}
+15
.sqlx/query-222699c46b99152404863463b8bdffb9452112e3d50ec352c96c1398d3e21504.json
+15
.sqlx/query-222699c46b99152404863463b8bdffb9452112e3d50ec352c96c1398d3e21504.json
···
···
1
+
{
2
+
"db_name": "PostgreSQL",
3
+
"query": "INSERT INTO invite_code_uses (code, used_by_user) VALUES ($1, $2)",
4
+
"describe": {
5
+
"columns": [],
6
+
"parameters": {
7
+
"Left": [
8
+
"Text",
9
+
"Uuid"
10
+
]
11
+
},
12
+
"nullable": []
13
+
},
14
+
"hash": "222699c46b99152404863463b8bdffb9452112e3d50ec352c96c1398d3e21504"
15
+
}
+46
.sqlx/query-2305db96343fcb721adc4a6a608b64678f707928d3f9395070f5e21a5ca9b601.json
+46
.sqlx/query-2305db96343fcb721adc4a6a608b64678f707928d3f9395070f5e21a5ca9b601.json
···
···
1
+
{
2
+
"db_name": "PostgreSQL",
3
+
"query": "SELECT u.id, u.did, u.handle, u.password_hash, k.key_bytes FROM users u JOIN user_keys k ON u.id = k.user_id WHERE u.handle = $1 OR u.email = $1",
4
+
"describe": {
5
+
"columns": [
6
+
{
7
+
"ordinal": 0,
8
+
"name": "id",
9
+
"type_info": "Uuid"
10
+
},
11
+
{
12
+
"ordinal": 1,
13
+
"name": "did",
14
+
"type_info": "Text"
15
+
},
16
+
{
17
+
"ordinal": 2,
18
+
"name": "handle",
19
+
"type_info": "Text"
20
+
},
21
+
{
22
+
"ordinal": 3,
23
+
"name": "password_hash",
24
+
"type_info": "Text"
25
+
},
26
+
{
27
+
"ordinal": 4,
28
+
"name": "key_bytes",
29
+
"type_info": "Bytea"
30
+
}
31
+
],
32
+
"parameters": {
33
+
"Left": [
34
+
"Text"
35
+
]
36
+
},
37
+
"nullable": [
38
+
false,
39
+
false,
40
+
false,
41
+
false,
42
+
false
43
+
]
44
+
},
45
+
"hash": "2305db96343fcb721adc4a6a608b64678f707928d3f9395070f5e21a5ca9b601"
46
+
}
+14
.sqlx/query-23201d4e26bc650939e30f69fb0bca00d351d057098afebc1017f70a84b4bd22.json
+14
.sqlx/query-23201d4e26bc650939e30f69fb0bca00d351d057098afebc1017f70a84b4bd22.json
···
···
1
+
{
2
+
"db_name": "PostgreSQL",
3
+
"query": "UPDATE users SET deactivated_at = NULL WHERE did = $1",
4
+
"describe": {
5
+
"columns": [],
6
+
"parameters": {
7
+
"Left": [
8
+
"Text"
9
+
]
10
+
},
11
+
"nullable": []
12
+
},
13
+
"hash": "23201d4e26bc650939e30f69fb0bca00d351d057098afebc1017f70a84b4bd22"
14
+
}
+23
.sqlx/query-423bbfd2ddf9b41d3bb339b8b94ac47524dc9233ec70cf2b6c5e9bc2de49b22d.json
+23
.sqlx/query-423bbfd2ddf9b41d3bb339b8b94ac47524dc9233ec70cf2b6c5e9bc2de49b22d.json
···
···
1
+
{
2
+
"db_name": "PostgreSQL",
3
+
"query": "SELECT 1 as one FROM blobs WHERE cid = $1 AND created_by_user = $2",
4
+
"describe": {
5
+
"columns": [
6
+
{
7
+
"ordinal": 0,
8
+
"name": "one",
9
+
"type_info": "Int4"
10
+
}
11
+
],
12
+
"parameters": {
13
+
"Left": [
14
+
"Text",
15
+
"Uuid"
16
+
]
17
+
},
18
+
"nullable": [
19
+
null
20
+
]
21
+
},
22
+
"hash": "423bbfd2ddf9b41d3bb339b8b94ac47524dc9233ec70cf2b6c5e9bc2de49b22d"
23
+
}
+34
.sqlx/query-47c914ca6080c5cedf0c3f6ca7cd4cd49e8fb691b34d19511b7a1ab8b3606cdf.json
+34
.sqlx/query-47c914ca6080c5cedf0c3f6ca7cd4cd49e8fb691b34d19511b7a1ab8b3606cdf.json
···
···
1
+
{
2
+
"db_name": "PostgreSQL",
3
+
"query": "\n SELECT s.did, k.key_bytes, u.handle\n FROM sessions s\n JOIN users u ON s.did = u.did\n JOIN user_keys k ON u.id = k.user_id\n WHERE s.access_jwt = $1\n ",
4
+
"describe": {
5
+
"columns": [
6
+
{
7
+
"ordinal": 0,
8
+
"name": "did",
9
+
"type_info": "Text"
10
+
},
11
+
{
12
+
"ordinal": 1,
13
+
"name": "key_bytes",
14
+
"type_info": "Bytea"
15
+
},
16
+
{
17
+
"ordinal": 2,
18
+
"name": "handle",
19
+
"type_info": "Text"
20
+
}
21
+
],
22
+
"parameters": {
23
+
"Left": [
24
+
"Text"
25
+
]
26
+
},
27
+
"nullable": [
28
+
false,
29
+
false,
30
+
false
31
+
]
32
+
},
33
+
"hash": "47c914ca6080c5cedf0c3f6ca7cd4cd49e8fb691b34d19511b7a1ab8b3606cdf"
34
+
}
+15
.sqlx/query-48915485884524f68783351bd61e9790dd7e729e5776adc66b9d0114bb8cd73a.json
+15
.sqlx/query-48915485884524f68783351bd61e9790dd7e729e5776adc66b9d0114bb8cd73a.json
···
···
1
+
{
2
+
"db_name": "PostgreSQL",
3
+
"query": "UPDATE users SET email = $1 WHERE did = $2",
4
+
"describe": {
5
+
"columns": [],
6
+
"parameters": {
7
+
"Left": [
8
+
"Text",
9
+
"Text"
10
+
]
11
+
},
12
+
"nullable": []
13
+
},
14
+
"hash": "48915485884524f68783351bd61e9790dd7e729e5776adc66b9d0114bb8cd73a"
15
+
}
+28
.sqlx/query-48ae289ec37b367a6ec3d74895acaf8c3dc93e65d243434b6947ead95ca8c416.json
+28
.sqlx/query-48ae289ec37b367a6ec3d74895acaf8c3dc93e65d243434b6947ead95ca8c416.json
···
···
1
+
{
2
+
"db_name": "PostgreSQL",
3
+
"query": "\n SELECT s.did, k.key_bytes\n FROM sessions s\n JOIN users u ON s.did = u.did\n JOIN user_keys k ON u.id = k.user_id\n WHERE s.access_jwt = $1\n ",
4
+
"describe": {
5
+
"columns": [
6
+
{
7
+
"ordinal": 0,
8
+
"name": "did",
9
+
"type_info": "Text"
10
+
},
11
+
{
12
+
"ordinal": 1,
13
+
"name": "key_bytes",
14
+
"type_info": "Bytea"
15
+
}
16
+
],
17
+
"parameters": {
18
+
"Left": [
19
+
"Text"
20
+
]
21
+
},
22
+
"nullable": [
23
+
false,
24
+
false
25
+
]
26
+
},
27
+
"hash": "48ae289ec37b367a6ec3d74895acaf8c3dc93e65d243434b6947ead95ca8c416"
28
+
}
+14
.sqlx/query-50293c2e54af11d4c2a553e29b671cef087a159c6ee7182d8ca929ecb748f3b7.json
+14
.sqlx/query-50293c2e54af11d4c2a553e29b671cef087a159c6ee7182d8ca929ecb748f3b7.json
···
+14
.sqlx/query-52437f0d7f91d29d7438263a1f658a838601038d911be8781b91ebeec8a54b89.json
+14
.sqlx/query-52437f0d7f91d29d7438263a1f658a838601038d911be8781b91ebeec8a54b89.json
···
···
1
+
{
2
+
"db_name": "PostgreSQL",
3
+
"query": "DELETE FROM sessions WHERE access_jwt = $1",
4
+
"describe": {
5
+
"columns": [],
6
+
"parameters": {
7
+
"Left": [
8
+
"Text"
9
+
]
10
+
},
11
+
"nullable": []
12
+
},
13
+
"hash": "52437f0d7f91d29d7438263a1f658a838601038d911be8781b91ebeec8a54b89"
14
+
}
+15
.sqlx/query-572b136b4196b7d755a252bc5bbf14b3765fc2e606b9512493e90efb4f1305fb.json
+15
.sqlx/query-572b136b4196b7d755a252bc5bbf14b3765fc2e606b9512493e90efb4f1305fb.json
···
···
1
+
{
2
+
"db_name": "PostgreSQL",
3
+
"query": "UPDATE users SET handle = $1 WHERE id = $2",
4
+
"describe": {
5
+
"columns": [],
6
+
"parameters": {
7
+
"Left": [
8
+
"Text",
9
+
"Uuid"
10
+
]
11
+
},
12
+
"nullable": []
13
+
},
14
+
"hash": "572b136b4196b7d755a252bc5bbf14b3765fc2e606b9512493e90efb4f1305fb"
15
+
}
+15
.sqlx/query-59e975c8599091b527ea2d097c68a8288360962d3e67f4db22e3dd92be924932.json
+15
.sqlx/query-59e975c8599091b527ea2d097c68a8288360962d3e67f4db22e3dd92be924932.json
···
···
1
+
{
2
+
"db_name": "PostgreSQL",
3
+
"query": "UPDATE users SET password_hash = $1 WHERE did = $2",
4
+
"describe": {
5
+
"columns": [],
6
+
"parameters": {
7
+
"Left": [
8
+
"Text",
9
+
"Text"
10
+
]
11
+
},
12
+
"nullable": []
13
+
},
14
+
"hash": "59e975c8599091b527ea2d097c68a8288360962d3e67f4db22e3dd92be924932"
15
+
}
+22
.sqlx/query-5b692e8f6d32dcbdcb45a3fff152a2be5672aadd807a4abab6914f80d57cba02.json
+22
.sqlx/query-5b692e8f6d32dcbdcb45a3fff152a2be5672aadd807a4abab6914f80d57cba02.json
···
···
1
+
{
2
+
"db_name": "PostgreSQL",
3
+
"query": "\n SELECT r.repo_root_cid\n FROM repos r\n JOIN users u ON r.user_id = u.id\n WHERE u.did = $1\n ",
4
+
"describe": {
5
+
"columns": [
6
+
{
7
+
"ordinal": 0,
8
+
"name": "repo_root_cid",
9
+
"type_info": "Text"
10
+
}
11
+
],
12
+
"parameters": {
13
+
"Left": [
14
+
"Text"
15
+
]
16
+
},
17
+
"nullable": [
18
+
false
19
+
]
20
+
},
21
+
"hash": "5b692e8f6d32dcbdcb45a3fff152a2be5672aadd807a4abab6914f80d57cba02"
22
+
}
+25
.sqlx/query-6c3a6dbf8d0d2a460054f093bd2ec1130ea91911d7d187cafcb4573be12bfcf4.json
+25
.sqlx/query-6c3a6dbf8d0d2a460054f093bd2ec1130ea91911d7d187cafcb4573be12bfcf4.json
···
···
1
+
{
2
+
"db_name": "PostgreSQL",
3
+
"query": "INSERT INTO users (handle, email, did, password_hash) VALUES ($1, $2, $3, $4) RETURNING id",
4
+
"describe": {
5
+
"columns": [
6
+
{
7
+
"ordinal": 0,
8
+
"name": "id",
9
+
"type_info": "Uuid"
10
+
}
11
+
],
12
+
"parameters": {
13
+
"Left": [
14
+
"Text",
15
+
"Text",
16
+
"Text",
17
+
"Text"
18
+
]
19
+
},
20
+
"nullable": [
21
+
false
22
+
]
23
+
},
24
+
"hash": "6c3a6dbf8d0d2a460054f093bd2ec1130ea91911d7d187cafcb4573be12bfcf4"
25
+
}
+23
.sqlx/query-6fd476d5640c20dc67db8e61e16b2f805e947ec404021cf93f6699f87bd7cfa5.json
+23
.sqlx/query-6fd476d5640c20dc67db8e61e16b2f805e947ec404021cf93f6699f87bd7cfa5.json
···
···
1
+
{
2
+
"db_name": "PostgreSQL",
3
+
"query": "SELECT id FROM users WHERE handle = $1 AND id != $2",
4
+
"describe": {
5
+
"columns": [
6
+
{
7
+
"ordinal": 0,
8
+
"name": "id",
9
+
"type_info": "Uuid"
10
+
}
11
+
],
12
+
"parameters": {
13
+
"Left": [
14
+
"Text",
15
+
"Uuid"
16
+
]
17
+
},
18
+
"nullable": [
19
+
false
20
+
]
21
+
},
22
+
"hash": "6fd476d5640c20dc67db8e61e16b2f805e947ec404021cf93f6699f87bd7cfa5"
23
+
}
+22
.sqlx/query-77dfbc702362db9bb87c9d17c4d985287d8faa024981ae26c995dfc53fb486fd.json
+22
.sqlx/query-77dfbc702362db9bb87c9d17c4d985287d8faa024981ae26c995dfc53fb486fd.json
···
···
1
+
{
2
+
"db_name": "PostgreSQL",
3
+
"query": "SELECT repo_root_cid FROM repos WHERE user_id = $1",
4
+
"describe": {
5
+
"columns": [
6
+
{
7
+
"ordinal": 0,
8
+
"name": "repo_root_cid",
9
+
"type_info": "Text"
10
+
}
11
+
],
12
+
"parameters": {
13
+
"Left": [
14
+
"Uuid"
15
+
]
16
+
},
17
+
"nullable": [
18
+
false
19
+
]
20
+
},
21
+
"hash": "77dfbc702362db9bb87c9d17c4d985287d8faa024981ae26c995dfc53fb486fd"
22
+
}
+14
.sqlx/query-7d0e11989d1b3f9c74daa3009505161369600509f103244fcd485b88869ee365.json
+14
.sqlx/query-7d0e11989d1b3f9c74daa3009505161369600509f103244fcd485b88869ee365.json
···
···
1
+
{
2
+
"db_name": "PostgreSQL",
3
+
"query": "DELETE FROM user_keys WHERE user_id = $1",
4
+
"describe": {
5
+
"columns": [],
6
+
"parameters": {
7
+
"Left": [
8
+
"Uuid"
9
+
]
10
+
},
11
+
"nullable": []
12
+
},
13
+
"hash": "7d0e11989d1b3f9c74daa3009505161369600509f103244fcd485b88869ee365"
14
+
}
+22
.sqlx/query-7d65d4608e93daa645ca0f8f6c7a23fb1bdaf50c7b0de900b1777542baf79d74.json
+22
.sqlx/query-7d65d4608e93daa645ca0f8f6c7a23fb1bdaf50c7b0de900b1777542baf79d74.json
···
···
1
+
{
2
+
"db_name": "PostgreSQL",
3
+
"query": "SELECT did FROM users WHERE handle = $1",
4
+
"describe": {
5
+
"columns": [
6
+
{
7
+
"ordinal": 0,
8
+
"name": "did",
9
+
"type_info": "Text"
10
+
}
11
+
],
12
+
"parameters": {
13
+
"Left": [
14
+
"Text"
15
+
]
16
+
},
17
+
"nullable": [
18
+
false
19
+
]
20
+
},
21
+
"hash": "7d65d4608e93daa645ca0f8f6c7a23fb1bdaf50c7b0de900b1777542baf79d74"
22
+
}
+14
.sqlx/query-824293a46fd22d2c6bf7dde85156214d561a95125ee3ba0f3bd6bb2c3a7625e5.json
+14
.sqlx/query-824293a46fd22d2c6bf7dde85156214d561a95125ee3ba0f3bd6bb2c3a7625e5.json
···
···
1
+
{
2
+
"db_name": "PostgreSQL",
3
+
"query": "DELETE FROM repos WHERE user_id = $1",
4
+
"describe": {
5
+
"columns": [],
6
+
"parameters": {
7
+
"Left": [
8
+
"Uuid"
9
+
]
10
+
},
11
+
"nullable": []
12
+
},
13
+
"hash": "824293a46fd22d2c6bf7dde85156214d561a95125ee3ba0f3bd6bb2c3a7625e5"
14
+
}
+22
.sqlx/query-8e69c8aebcb15c6956b8a0b9324dcc8668b2e14731945ceaf30b756050be9882.json
+22
.sqlx/query-8e69c8aebcb15c6956b8a0b9324dcc8668b2e14731945ceaf30b756050be9882.json
···
···
1
+
{
2
+
"db_name": "PostgreSQL",
3
+
"query": "SELECT id FROM users WHERE did = $1",
4
+
"describe": {
5
+
"columns": [
6
+
{
7
+
"ordinal": 0,
8
+
"name": "id",
9
+
"type_info": "Uuid"
10
+
}
11
+
],
12
+
"parameters": {
13
+
"Left": [
14
+
"Text"
15
+
]
16
+
},
17
+
"nullable": [
18
+
false
19
+
]
20
+
},
21
+
"hash": "8e69c8aebcb15c6956b8a0b9324dcc8668b2e14731945ceaf30b756050be9882"
22
+
}
+14
.sqlx/query-997cff04226e18bf4d5025092d0daf0450292bcbdba21b8530706797144dcafa.json
+14
.sqlx/query-997cff04226e18bf4d5025092d0daf0450292bcbdba21b8530706797144dcafa.json
···
···
1
+
{
2
+
"db_name": "PostgreSQL",
3
+
"query": "DELETE FROM blobs WHERE created_by_user = $1",
4
+
"describe": {
5
+
"columns": [],
6
+
"parameters": {
7
+
"Left": [
8
+
"Uuid"
9
+
]
10
+
},
11
+
"nullable": []
12
+
},
13
+
"hash": "997cff04226e18bf4d5025092d0daf0450292bcbdba21b8530706797144dcafa"
14
+
}
+14
.sqlx/query-9c42b607a971b3a102d247def6c6fd322013f3885e9d0232d6e846220f893c49.json
+14
.sqlx/query-9c42b607a971b3a102d247def6c6fd322013f3885e9d0232d6e846220f893c49.json
···
···
1
+
{
2
+
"db_name": "PostgreSQL",
3
+
"query": "DELETE FROM sessions WHERE did = $1",
4
+
"describe": {
5
+
"columns": [],
6
+
"parameters": {
7
+
"Left": [
8
+
"Text"
9
+
]
10
+
},
11
+
"nullable": []
12
+
},
13
+
"hash": "9c42b607a971b3a102d247def6c6fd322013f3885e9d0232d6e846220f893c49"
14
+
}
+16
.sqlx/query-a5b7ceaa177ef136a0e2421eaca3f3edf283e9305bd4675d72a1b7a02c3dfc83.json
+16
.sqlx/query-a5b7ceaa177ef136a0e2421eaca3f3edf283e9305bd4675d72a1b7a02c3dfc83.json
···
···
1
+
{
2
+
"db_name": "PostgreSQL",
3
+
"query": "UPDATE sessions SET access_jwt = $1, refresh_jwt = $2 WHERE refresh_jwt = $3",
4
+
"describe": {
5
+
"columns": [],
6
+
"parameters": {
7
+
"Left": [
8
+
"Text",
9
+
"Text",
10
+
"Text"
11
+
]
12
+
},
13
+
"nullable": []
14
+
},
15
+
"hash": "a5b7ceaa177ef136a0e2421eaca3f3edf283e9305bd4675d72a1b7a02c3dfc83"
16
+
}
+14
.sqlx/query-a802bf661ef9a9baa41604b31e3cca9067ca467faef9c952e98db418157c0642.json
+14
.sqlx/query-a802bf661ef9a9baa41604b31e3cca9067ca467faef9c952e98db418157c0642.json
···
···
1
+
{
2
+
"db_name": "PostgreSQL",
3
+
"query": "UPDATE users SET deactivated_at = NOW() WHERE did = $1",
4
+
"describe": {
5
+
"columns": [],
6
+
"parameters": {
7
+
"Left": [
8
+
"Text"
9
+
]
10
+
},
11
+
"nullable": []
12
+
},
13
+
"hash": "a802bf661ef9a9baa41604b31e3cca9067ca467faef9c952e98db418157c0642"
14
+
}
+15
.sqlx/query-aac3acbfc4f27b98054602de28b763ce15e3a70a9e6741114d12f2d173f631fe.json
+15
.sqlx/query-aac3acbfc4f27b98054602de28b763ce15e3a70a9e6741114d12f2d173f631fe.json
···
···
1
+
{
2
+
"db_name": "PostgreSQL",
3
+
"query": "UPDATE users SET handle = $1 WHERE did = $2",
4
+
"describe": {
5
+
"columns": [],
6
+
"parameters": {
7
+
"Left": [
8
+
"Text",
9
+
"Text"
10
+
]
11
+
},
12
+
"nullable": []
13
+
},
14
+
"hash": "aac3acbfc4f27b98054602de28b763ce15e3a70a9e6741114d12f2d173f631fe"
15
+
}
+28
.sqlx/query-b2c53e6a278c4549c99a5b98cc7ca77fc1e9cd39a591c1d8ec1ca41adfffa3a6.json
+28
.sqlx/query-b2c53e6a278c4549c99a5b98cc7ca77fc1e9cd39a591c1d8ec1ca41adfffa3a6.json
···
···
1
+
{
2
+
"db_name": "PostgreSQL",
3
+
"query": "SELECT id, did FROM users WHERE handle = $1",
4
+
"describe": {
5
+
"columns": [
6
+
{
7
+
"ordinal": 0,
8
+
"name": "id",
9
+
"type_info": "Uuid"
10
+
},
11
+
{
12
+
"ordinal": 1,
13
+
"name": "did",
14
+
"type_info": "Text"
15
+
}
16
+
],
17
+
"parameters": {
18
+
"Left": [
19
+
"Text"
20
+
]
21
+
},
22
+
"nullable": [
23
+
false,
24
+
false
25
+
]
26
+
},
27
+
"hash": "b2c53e6a278c4549c99a5b98cc7ca77fc1e9cd39a591c1d8ec1ca41adfffa3a6"
28
+
}
+28
.sqlx/query-bb243abd63d10a43b11fa4f93644149f315894496255c5538f131b2c7aeb763b.json
+28
.sqlx/query-bb243abd63d10a43b11fa4f93644149f315894496255c5538f131b2c7aeb763b.json
···
···
1
+
{
2
+
"db_name": "PostgreSQL",
3
+
"query": "SELECT storage_key, mime_type FROM blobs WHERE cid = $1",
4
+
"describe": {
5
+
"columns": [
6
+
{
7
+
"ordinal": 0,
8
+
"name": "storage_key",
9
+
"type_info": "Text"
10
+
},
11
+
{
12
+
"ordinal": 1,
13
+
"name": "mime_type",
14
+
"type_info": "Text"
15
+
}
16
+
],
17
+
"parameters": {
18
+
"Left": [
19
+
"Text"
20
+
]
21
+
},
22
+
"nullable": [
23
+
false,
24
+
false
25
+
]
26
+
},
27
+
"hash": "bb243abd63d10a43b11fa4f93644149f315894496255c5538f131b2c7aeb763b"
28
+
}
+22
.sqlx/query-bf2b237ee5cfe66d038dce3f564c05a683d391aebda7871d65d302e04b5d733f.json
+22
.sqlx/query-bf2b237ee5cfe66d038dce3f564c05a683d391aebda7871d65d302e04b5d733f.json
···
···
1
+
{
2
+
"db_name": "PostgreSQL",
3
+
"query": "SELECT deactivated_at FROM users WHERE did = $1",
4
+
"describe": {
5
+
"columns": [
6
+
{
7
+
"ordinal": 0,
8
+
"name": "deactivated_at",
9
+
"type_info": "Timestamptz"
10
+
}
11
+
],
12
+
"parameters": {
13
+
"Left": [
14
+
"Text"
15
+
]
16
+
},
17
+
"nullable": [
18
+
true
19
+
]
20
+
},
21
+
"hash": "bf2b237ee5cfe66d038dce3f564c05a683d391aebda7871d65d302e04b5d733f"
22
+
}
+24
.sqlx/query-bf55c87dfdeb7bc18663a50d10eeee0e53fade51c1c47bed9580072435baefea.json
+24
.sqlx/query-bf55c87dfdeb7bc18663a50d10eeee0e53fade51c1c47bed9580072435baefea.json
···
···
1
+
{
2
+
"db_name": "PostgreSQL",
3
+
"query": "\n SELECT cid FROM blobs\n WHERE created_by_user = $1 AND cid > $2\n ORDER BY cid ASC\n LIMIT $3\n ",
4
+
"describe": {
5
+
"columns": [
6
+
{
7
+
"ordinal": 0,
8
+
"name": "cid",
9
+
"type_info": "Text"
10
+
}
11
+
],
12
+
"parameters": {
13
+
"Left": [
14
+
"Uuid",
15
+
"Text",
16
+
"Int8"
17
+
]
18
+
},
19
+
"nullable": [
20
+
false
21
+
]
22
+
},
23
+
"hash": "bf55c87dfdeb7bc18663a50d10eeee0e53fade51c1c47bed9580072435baefea"
24
+
}
+22
.sqlx/query-bf60faafb5c79a149ba237a984f78d068b5d691f6762641412a5aa1517605c04.json
+22
.sqlx/query-bf60faafb5c79a149ba237a984f78d068b5d691f6762641412a5aa1517605c04.json
···
···
1
+
{
2
+
"db_name": "PostgreSQL",
3
+
"query": "SELECT record_cid FROM records WHERE repo_id = $1 AND collection = 'app.bsky.graph.follow'",
4
+
"describe": {
5
+
"columns": [
6
+
{
7
+
"ordinal": 0,
8
+
"name": "record_cid",
9
+
"type_info": "Text"
10
+
}
11
+
],
12
+
"parameters": {
13
+
"Left": [
14
+
"Uuid"
15
+
]
16
+
},
17
+
"nullable": [
18
+
false
19
+
]
20
+
},
21
+
"hash": "bf60faafb5c79a149ba237a984f78d068b5d691f6762641412a5aa1517605c04"
22
+
}
+40
.sqlx/query-c2a90157c47bf1c36f08f4608932d214cc26b4794e0b922b1dae3dad18a7ddc0.json
+40
.sqlx/query-c2a90157c47bf1c36f08f4608932d214cc26b4794e0b922b1dae3dad18a7ddc0.json
···
···
1
+
{
2
+
"db_name": "PostgreSQL",
3
+
"query": "\n SELECT did, handle, email, created_at\n FROM users\n WHERE did = $1\n ",
4
+
"describe": {
5
+
"columns": [
6
+
{
7
+
"ordinal": 0,
8
+
"name": "did",
9
+
"type_info": "Text"
10
+
},
11
+
{
12
+
"ordinal": 1,
13
+
"name": "handle",
14
+
"type_info": "Text"
15
+
},
16
+
{
17
+
"ordinal": 2,
18
+
"name": "email",
19
+
"type_info": "Text"
20
+
},
21
+
{
22
+
"ordinal": 3,
23
+
"name": "created_at",
24
+
"type_info": "Timestamptz"
25
+
}
26
+
],
27
+
"parameters": {
28
+
"Left": [
29
+
"Text"
30
+
]
31
+
},
32
+
"nullable": [
33
+
false,
34
+
false,
35
+
false,
36
+
false
37
+
]
38
+
},
39
+
"hash": "c2a90157c47bf1c36f08f4608932d214cc26b4794e0b922b1dae3dad18a7ddc0"
40
+
}
+15
.sqlx/query-c4c9842e69c5fd4f4a2ebc176078af2a5f98beb3ea4d3c6af5b1b8fed2ec50e3.json
+15
.sqlx/query-c4c9842e69c5fd4f4a2ebc176078af2a5f98beb3ea4d3c6af5b1b8fed2ec50e3.json
···
···
1
+
{
2
+
"db_name": "PostgreSQL",
3
+
"query": "INSERT INTO user_keys (user_id, key_bytes) VALUES ($1, $2)",
4
+
"describe": {
5
+
"columns": [],
6
+
"parameters": {
7
+
"Left": [
8
+
"Uuid",
9
+
"Bytea"
10
+
]
11
+
},
12
+
"nullable": []
13
+
},
14
+
"hash": "c4c9842e69c5fd4f4a2ebc176078af2a5f98beb3ea4d3c6af5b1b8fed2ec50e3"
15
+
}
+28
.sqlx/query-c949b23cf6d795c58e4c35907628bbb85714e9c49a569653b17acab60e1674ac.json
+28
.sqlx/query-c949b23cf6d795c58e4c35907628bbb85714e9c49a569653b17acab60e1674ac.json
···
···
1
+
{
2
+
"db_name": "PostgreSQL",
3
+
"query": "SELECT s.did, k.key_bytes FROM sessions s JOIN users u ON s.did = u.did JOIN user_keys k ON u.id = k.user_id WHERE s.refresh_jwt = $1",
4
+
"describe": {
5
+
"columns": [
6
+
{
7
+
"ordinal": 0,
8
+
"name": "did",
9
+
"type_info": "Text"
10
+
},
11
+
{
12
+
"ordinal": 1,
13
+
"name": "key_bytes",
14
+
"type_info": "Bytea"
15
+
}
16
+
],
17
+
"parameters": {
18
+
"Left": [
19
+
"Text"
20
+
]
21
+
},
22
+
"nullable": [
23
+
false,
24
+
false
25
+
]
26
+
},
27
+
"hash": "c949b23cf6d795c58e4c35907628bbb85714e9c49a569653b17acab60e1674ac"
28
+
}
+22
.sqlx/query-ce27e2da1f15cad97d2e31fda964e1d7017154fa559a8d9851728fb23af871cd.json
+22
.sqlx/query-ce27e2da1f15cad97d2e31fda964e1d7017154fa559a8d9851728fb23af871cd.json
···
···
1
+
{
2
+
"db_name": "PostgreSQL",
3
+
"query": "SELECT key_bytes FROM user_keys WHERE user_id = $1",
4
+
"describe": {
5
+
"columns": [
6
+
{
7
+
"ordinal": 0,
8
+
"name": "key_bytes",
9
+
"type_info": "Bytea"
10
+
}
11
+
],
12
+
"parameters": {
13
+
"Left": [
14
+
"Uuid"
15
+
]
16
+
},
17
+
"nullable": [
18
+
false
19
+
]
20
+
},
21
+
"hash": "ce27e2da1f15cad97d2e31fda964e1d7017154fa559a8d9851728fb23af871cd"
22
+
}
+34
.sqlx/query-cec87a805457bcac6db8be601861b351a9332c649433894547176f6e4d672d01.json
+34
.sqlx/query-cec87a805457bcac6db8be601861b351a9332c649433894547176f6e4d672d01.json
···
···
1
+
{
2
+
"db_name": "PostgreSQL",
3
+
"query": "SELECT name, created_at, privileged FROM app_passwords WHERE user_id = $1 ORDER BY created_at DESC",
4
+
"describe": {
5
+
"columns": [
6
+
{
7
+
"ordinal": 0,
8
+
"name": "name",
9
+
"type_info": "Text"
10
+
},
11
+
{
12
+
"ordinal": 1,
13
+
"name": "created_at",
14
+
"type_info": "Timestamptz"
15
+
},
16
+
{
17
+
"ordinal": 2,
18
+
"name": "privileged",
19
+
"type_info": "Bool"
20
+
}
21
+
],
22
+
"parameters": {
23
+
"Left": [
24
+
"Uuid"
25
+
]
26
+
},
27
+
"nullable": [
28
+
false,
29
+
false,
30
+
false
31
+
]
32
+
},
33
+
"hash": "cec87a805457bcac6db8be601861b351a9332c649433894547176f6e4d672d01"
34
+
}
+34
.sqlx/query-d31423ddcb625250d7c15581e8c9242ec6290b41507eb710744ad900d482222d.json
+34
.sqlx/query-d31423ddcb625250d7c15581e8c9242ec6290b41507eb710744ad900d482222d.json
···
···
1
+
{
2
+
"db_name": "PostgreSQL",
3
+
"query": "\n SELECT s.did, k.key_bytes, u.id as user_id\n FROM sessions s\n JOIN users u ON s.did = u.did\n JOIN user_keys k ON u.id = k.user_id\n WHERE s.access_jwt = $1\n ",
4
+
"describe": {
5
+
"columns": [
6
+
{
7
+
"ordinal": 0,
8
+
"name": "did",
9
+
"type_info": "Text"
10
+
},
11
+
{
12
+
"ordinal": 1,
13
+
"name": "key_bytes",
14
+
"type_info": "Bytea"
15
+
},
16
+
{
17
+
"ordinal": 2,
18
+
"name": "user_id",
19
+
"type_info": "Uuid"
20
+
}
21
+
],
22
+
"parameters": {
23
+
"Left": [
24
+
"Text"
25
+
]
26
+
},
27
+
"nullable": [
28
+
false,
29
+
false,
30
+
false
31
+
]
32
+
},
33
+
"hash": "d31423ddcb625250d7c15581e8c9242ec6290b41507eb710744ad900d482222d"
34
+
}
+16
.sqlx/query-db9950690548510474a2bf755b4c4c103b284e82e3cf23d17fc99cd2fc728c64.json
+16
.sqlx/query-db9950690548510474a2bf755b4c4c103b284e82e3cf23d17fc99cd2fc728c64.json
···
···
1
+
{
2
+
"db_name": "PostgreSQL",
3
+
"query": "INSERT INTO sessions (access_jwt, refresh_jwt, did) VALUES ($1, $2, $3)",
4
+
"describe": {
5
+
"columns": [],
6
+
"parameters": {
7
+
"Left": [
8
+
"Text",
9
+
"Text",
10
+
"Text"
11
+
]
12
+
},
13
+
"nullable": []
14
+
},
15
+
"hash": "db9950690548510474a2bf755b4c4c103b284e82e3cf23d17fc99cd2fc728c64"
16
+
}
+22
.sqlx/query-e2746221a24351293447246af539b5a847129cf93233dd98161193d4b7156b45.json
+22
.sqlx/query-e2746221a24351293447246af539b5a847129cf93233dd98161193d4b7156b45.json
···
···
1
+
{
2
+
"db_name": "PostgreSQL",
3
+
"query": "SELECT available_uses FROM invite_codes WHERE code = $1 FOR UPDATE",
4
+
"describe": {
5
+
"columns": [
6
+
{
7
+
"ordinal": 0,
8
+
"name": "available_uses",
9
+
"type_info": "Int4"
10
+
}
11
+
],
12
+
"parameters": {
13
+
"Left": [
14
+
"Text"
15
+
]
16
+
},
17
+
"nullable": [
18
+
false
19
+
]
20
+
},
21
+
"hash": "e2746221a24351293447246af539b5a847129cf93233dd98161193d4b7156b45"
22
+
}
+23
.sqlx/query-e80274b0731ed0ff9a1a1ae444eefadc193a172795b41c71445717020e6367d6.json
+23
.sqlx/query-e80274b0731ed0ff9a1a1ae444eefadc193a172795b41c71445717020e6367d6.json
···
···
1
+
{
2
+
"db_name": "PostgreSQL",
3
+
"query": "SELECT id FROM users WHERE handle = $1 AND did != $2",
4
+
"describe": {
5
+
"columns": [
6
+
{
7
+
"ordinal": 0,
8
+
"name": "id",
9
+
"type_info": "Uuid"
10
+
}
11
+
],
12
+
"parameters": {
13
+
"Left": [
14
+
"Text",
15
+
"Text"
16
+
]
17
+
},
18
+
"nullable": [
19
+
false
20
+
]
21
+
},
22
+
"hash": "e80274b0731ed0ff9a1a1ae444eefadc193a172795b41c71445717020e6367d6"
23
+
}
+22
.sqlx/query-ec5e14110d69ba47e8dd4447569c31506220df7759d0449e20d224609c7e6c4c.json
+22
.sqlx/query-ec5e14110d69ba47e8dd4447569c31506220df7759d0449e20d224609c7e6c4c.json
···
···
1
+
{
2
+
"db_name": "PostgreSQL",
3
+
"query": "SELECT handle FROM users WHERE did = $1",
4
+
"describe": {
5
+
"columns": [
6
+
{
7
+
"ordinal": 0,
8
+
"name": "handle",
9
+
"type_info": "Text"
10
+
}
11
+
],
12
+
"parameters": {
13
+
"Left": [
14
+
"Text"
15
+
]
16
+
},
17
+
"nullable": [
18
+
false
19
+
]
20
+
},
21
+
"hash": "ec5e14110d69ba47e8dd4447569c31506220df7759d0449e20d224609c7e6c4c"
22
+
}
+22
.sqlx/query-ed34111a7f41b419a23d16ddd23cbc6aff9ab373946ff243512c52f857b7980d.json
+22
.sqlx/query-ed34111a7f41b419a23d16ddd23cbc6aff9ab373946ff243512c52f857b7980d.json
···
···
1
+
{
2
+
"db_name": "PostgreSQL",
3
+
"query": "SELECT 1 as one FROM users WHERE handle = $1",
4
+
"describe": {
5
+
"columns": [
6
+
{
7
+
"ordinal": 0,
8
+
"name": "one",
9
+
"type_info": "Int4"
10
+
}
11
+
],
12
+
"parameters": {
13
+
"Left": [
14
+
"Text"
15
+
]
16
+
},
17
+
"nullable": [
18
+
null
19
+
]
20
+
},
21
+
"hash": "ed34111a7f41b419a23d16ddd23cbc6aff9ab373946ff243512c52f857b7980d"
22
+
}
+23
.sqlx/query-eecc3bc506aafe17d7804b9749dc00bd9fedcb148d2a339bbf7ffba08541e8f6.json
+23
.sqlx/query-eecc3bc506aafe17d7804b9749dc00bd9fedcb148d2a339bbf7ffba08541e8f6.json
···
···
1
+
{
2
+
"db_name": "PostgreSQL",
3
+
"query": "SELECT id FROM app_passwords WHERE user_id = $1 AND name = $2",
4
+
"describe": {
5
+
"columns": [
6
+
{
7
+
"ordinal": 0,
8
+
"name": "id",
9
+
"type_info": "Uuid"
10
+
}
11
+
],
12
+
"parameters": {
13
+
"Left": [
14
+
"Uuid",
15
+
"Text"
16
+
]
17
+
},
18
+
"nullable": [
19
+
false
20
+
]
21
+
},
22
+
"hash": "eecc3bc506aafe17d7804b9749dc00bd9fedcb148d2a339bbf7ffba08541e8f6"
23
+
}
+14
.sqlx/query-eed03ee02de1828a665bc268ba135511005416b122bccb79374204a8023ace41.json
+14
.sqlx/query-eed03ee02de1828a665bc268ba135511005416b122bccb79374204a8023ace41.json
···
···
1
+
{
2
+
"db_name": "PostgreSQL",
3
+
"query": "DELETE FROM records WHERE repo_id = $1",
4
+
"describe": {
5
+
"columns": [],
6
+
"parameters": {
7
+
"Left": [
8
+
"Uuid"
9
+
]
10
+
},
11
+
"nullable": []
12
+
},
13
+
"hash": "eed03ee02de1828a665bc268ba135511005416b122bccb79374204a8023ace41"
14
+
}
+22
.sqlx/query-ef55a06bcea9b1a0d744df4fe353260ae4d6d93bbf5ea73133db65e38f6241ee.json
+22
.sqlx/query-ef55a06bcea9b1a0d744df4fe353260ae4d6d93bbf5ea73133db65e38f6241ee.json
···
···
1
+
{
2
+
"db_name": "PostgreSQL",
3
+
"query": "SELECT k.key_bytes FROM user_keys k JOIN users u ON k.user_id = u.id WHERE u.did = $1",
4
+
"describe": {
5
+
"columns": [
6
+
{
7
+
"ordinal": 0,
8
+
"name": "key_bytes",
9
+
"type_info": "Bytea"
10
+
}
11
+
],
12
+
"parameters": {
13
+
"Left": [
14
+
"Text"
15
+
]
16
+
},
17
+
"nullable": [
18
+
false
19
+
]
20
+
},
21
+
"hash": "ef55a06bcea9b1a0d744df4fe353260ae4d6d93bbf5ea73133db65e38f6241ee"
22
+
}
+15
.sqlx/query-f1d4742aaa1d48f4a944d50743a51b0938cec852d0238347883dc110050e8d3a.json
+15
.sqlx/query-f1d4742aaa1d48f4a944d50743a51b0938cec852d0238347883dc110050e8d3a.json
···
···
1
+
{
2
+
"db_name": "PostgreSQL",
3
+
"query": "DELETE FROM app_passwords WHERE user_id = $1 AND name = $2",
4
+
"describe": {
5
+
"columns": [],
6
+
"parameters": {
7
+
"Left": [
8
+
"Uuid",
9
+
"Text"
10
+
]
11
+
},
12
+
"nullable": []
13
+
},
14
+
"hash": "f1d4742aaa1d48f4a944d50743a51b0938cec852d0238347883dc110050e8d3a"
15
+
}
+22
.sqlx/query-f8bee08776a6e246bdee70c0452217e8b654bf8617524edb4add139582b966ac.json
+22
.sqlx/query-f8bee08776a6e246bdee70c0452217e8b654bf8617524edb4add139582b966ac.json
···
···
1
+
{
2
+
"db_name": "PostgreSQL",
3
+
"query": "SELECT password_hash FROM app_passwords WHERE user_id = $1",
4
+
"describe": {
5
+
"columns": [
6
+
{
7
+
"ordinal": 0,
8
+
"name": "password_hash",
9
+
"type_info": "Text"
10
+
}
11
+
],
12
+
"parameters": {
13
+
"Left": [
14
+
"Uuid"
15
+
]
16
+
},
17
+
"nullable": [
18
+
false
19
+
]
20
+
},
21
+
"hash": "f8bee08776a6e246bdee70c0452217e8b654bf8617524edb4add139582b966ac"
22
+
}
+28
.sqlx/query-f91a07e40484ade5b4c72addf62e4ad82feab312645c0b7a4ea69c0e55e17b14.json
+28
.sqlx/query-f91a07e40484ade5b4c72addf62e4ad82feab312645c0b7a4ea69c0e55e17b14.json
···
···
1
+
{
2
+
"db_name": "PostgreSQL",
3
+
"query": "SELECT s.did, k.key_bytes FROM sessions s JOIN users u ON s.did = u.did JOIN user_keys k ON u.id = k.user_id WHERE s.access_jwt = $1",
4
+
"describe": {
5
+
"columns": [
6
+
{
7
+
"ordinal": 0,
8
+
"name": "did",
9
+
"type_info": "Text"
10
+
},
11
+
{
12
+
"ordinal": 1,
13
+
"name": "key_bytes",
14
+
"type_info": "Bytea"
15
+
}
16
+
],
17
+
"parameters": {
18
+
"Left": [
19
+
"Text"
20
+
]
21
+
},
22
+
"nullable": [
23
+
false,
24
+
false
25
+
]
26
+
},
27
+
"hash": "f91a07e40484ade5b4c72addf62e4ad82feab312645c0b7a4ea69c0e55e17b14"
28
+
}
+22
.sqlx/query-fa09feeb85d8648a8ebf339a69114ab6b3c6336642d6907ed4549b601e401f82.json
+22
.sqlx/query-fa09feeb85d8648a8ebf339a69114ab6b3c6336642d6907ed4549b601e401f82.json
···
···
1
+
{
2
+
"db_name": "PostgreSQL",
3
+
"query": "SELECT COUNT(*) FROM records WHERE repo_id = $1",
4
+
"describe": {
5
+
"columns": [
6
+
{
7
+
"ordinal": 0,
8
+
"name": "count",
9
+
"type_info": "Int8"
10
+
}
11
+
],
12
+
"parameters": {
13
+
"Left": [
14
+
"Uuid"
15
+
]
16
+
},
17
+
"nullable": [
18
+
null
19
+
]
20
+
},
21
+
"hash": "fa09feeb85d8648a8ebf339a69114ab6b3c6336642d6907ed4549b601e401f82"
22
+
}
+19
.sqlx/query-fc06fa0ba9ae769e68c7386a9236995fe678a15e63a692b8460d692b242ea3c7.json
+19
.sqlx/query-fc06fa0ba9ae769e68c7386a9236995fe678a15e63a692b8460d692b242ea3c7.json
···
···
1
+
{
2
+
"db_name": "PostgreSQL",
3
+
"query": "INSERT INTO reports (id, reason_type, reason, subject_json, reported_by_did, created_at) VALUES ($1, $2, $3, $4, $5, $6)",
4
+
"describe": {
5
+
"columns": [],
6
+
"parameters": {
7
+
"Left": [
8
+
"Int8",
9
+
"Text",
10
+
"Text",
11
+
"Jsonb",
12
+
"Text",
13
+
"Timestamptz"
14
+
]
15
+
},
16
+
"nullable": []
17
+
},
18
+
"hash": "fc06fa0ba9ae769e68c7386a9236995fe678a15e63a692b8460d692b242ea3c7"
19
+
}
+22
.sqlx/query-fd42681b7af9c795643baf65a998a55822ea81a07b651385740401f62bf8a8ae.json
+22
.sqlx/query-fd42681b7af9c795643baf65a998a55822ea81a07b651385740401f62bf8a8ae.json
···
···
1
+
{
2
+
"db_name": "PostgreSQL",
3
+
"query": "SELECT COUNT(*) FROM blobs WHERE created_by_user = $1",
4
+
"describe": {
5
+
"columns": [
6
+
{
7
+
"ordinal": 0,
8
+
"name": "count",
9
+
"type_info": "Int8"
10
+
}
11
+
],
12
+
"parameters": {
13
+
"Left": [
14
+
"Uuid"
15
+
]
16
+
},
17
+
"nullable": [
18
+
null
19
+
]
20
+
},
21
+
"hash": "fd42681b7af9c795643baf65a998a55822ea81a07b651385740401f62bf8a8ae"
22
+
}
+37
.sqlx/query-ff7899984ea138f1e608fa862def47402369a428ac9116c653890e5fcaa0015b.json
+37
.sqlx/query-ff7899984ea138f1e608fa862def47402369a428ac9116c653890e5fcaa0015b.json
···
···
1
+
{
2
+
"db_name": "PostgreSQL",
3
+
"query": "SELECT collection, rkey, record_cid FROM records WHERE repo_id = $1 AND (collection, rkey) > ($2, $3) ORDER BY collection, rkey LIMIT $4",
4
+
"describe": {
5
+
"columns": [
6
+
{
7
+
"ordinal": 0,
8
+
"name": "collection",
9
+
"type_info": "Text"
10
+
},
11
+
{
12
+
"ordinal": 1,
13
+
"name": "rkey",
14
+
"type_info": "Text"
15
+
},
16
+
{
17
+
"ordinal": 2,
18
+
"name": "record_cid",
19
+
"type_info": "Text"
20
+
}
21
+
],
22
+
"parameters": {
23
+
"Left": [
24
+
"Uuid",
25
+
"Text",
26
+
"Text",
27
+
"Int8"
28
+
]
29
+
},
30
+
"nullable": [
31
+
false,
32
+
false,
33
+
false
34
+
]
35
+
},
36
+
"hash": "ff7899984ea138f1e608fa862def47402369a428ac9116c653890e5fcaa0015b"
37
+
}
+25
-51
src/api/admin/mod.rs
+25
-51
src/api/admin/mod.rs
···
7
};
8
use serde::{Deserialize, Serialize};
9
use serde_json::json;
10
-
use sqlx::Row;
11
use tracing::error;
12
13
#[derive(Deserialize)]
···
57
.into_response();
58
}
59
60
-
let result = sqlx::query(
61
r#"
62
SELECT did, handle, email, created_at
63
FROM users
64
WHERE did = $1
65
"#,
66
)
67
-
.bind(did)
68
.fetch_optional(&state.db)
69
.await;
70
71
match result {
72
Ok(Some(row)) => {
73
-
let user_did: String = row.get("did");
74
-
let handle: String = row.get("handle");
75
-
let email: String = row.get("email");
76
-
let created_at: chrono::DateTime<chrono::Utc> = row.get("created_at");
77
-
78
(
79
StatusCode::OK,
80
Json(AccountInfo {
81
-
did: user_did,
82
-
handle,
83
-
email: Some(email),
84
-
indexed_at: created_at.to_rfc3339(),
85
invite_note: None,
86
invites_disabled: false,
87
email_confirmed_at: None,
···
141
continue;
142
}
143
144
-
let result = sqlx::query(
145
r#"
146
SELECT did, handle, email, created_at
147
FROM users
148
WHERE did = $1
149
"#,
150
)
151
-
.bind(did)
152
.fetch_optional(&state.db)
153
.await;
154
155
if let Ok(Some(row)) = result {
156
-
let user_did: String = row.get("did");
157
-
let handle: String = row.get("handle");
158
-
let email: String = row.get("email");
159
-
let created_at: chrono::DateTime<chrono::Utc> = row.get("created_at");
160
-
161
infos.push(AccountInfo {
162
-
did: user_did,
163
-
handle,
164
-
email: Some(email),
165
-
indexed_at: created_at.to_rfc3339(),
166
invite_note: None,
167
invites_disabled: false,
168
email_confirmed_at: None,
···
202
.into_response();
203
}
204
205
-
let user = sqlx::query("SELECT id FROM users WHERE did = $1")
206
-
.bind(did)
207
.fetch_optional(&state.db)
208
.await;
209
210
-
let user_id: uuid::Uuid = match user {
211
-
Ok(Some(row)) => row.get("id"),
212
Ok(None) => {
213
return (
214
StatusCode::NOT_FOUND,
···
226
}
227
};
228
229
-
let _ = sqlx::query("DELETE FROM sessions WHERE did = $1")
230
-
.bind(did)
231
.execute(&state.db)
232
.await;
233
234
-
let _ = sqlx::query("DELETE FROM records WHERE repo_id = $1")
235
-
.bind(user_id)
236
.execute(&state.db)
237
.await;
238
239
-
let _ = sqlx::query("DELETE FROM repos WHERE user_id = $1")
240
-
.bind(user_id)
241
.execute(&state.db)
242
.await;
243
244
-
let _ = sqlx::query("DELETE FROM blobs WHERE created_by_user = $1")
245
-
.bind(user_id)
246
.execute(&state.db)
247
.await;
248
249
-
let _ = sqlx::query("DELETE FROM user_keys WHERE user_id = $1")
250
-
.bind(user_id)
251
.execute(&state.db)
252
.await;
253
254
-
let result = sqlx::query("DELETE FROM users WHERE id = $1")
255
-
.bind(user_id)
256
.execute(&state.db)
257
.await;
258
···
300
.into_response();
301
}
302
303
-
let result = sqlx::query("UPDATE users SET email = $1 WHERE did = $2")
304
-
.bind(email)
305
-
.bind(account)
306
.execute(&state.db)
307
.await;
308
···
370
.into_response();
371
}
372
373
-
let existing = sqlx::query("SELECT id FROM users WHERE handle = $1 AND did != $2")
374
-
.bind(handle)
375
-
.bind(did)
376
.fetch_optional(&state.db)
377
.await;
378
···
384
.into_response();
385
}
386
387
-
let result = sqlx::query("UPDATE users SET handle = $1 WHERE did = $2")
388
-
.bind(handle)
389
-
.bind(did)
390
.execute(&state.db)
391
.await;
392
···
455
}
456
};
457
458
-
let result = sqlx::query("UPDATE users SET password_hash = $1 WHERE did = $2")
459
-
.bind(&password_hash)
460
-
.bind(did)
461
.execute(&state.db)
462
.await;
463
···
7
};
8
use serde::{Deserialize, Serialize};
9
use serde_json::json;
10
use tracing::error;
11
12
#[derive(Deserialize)]
···
56
.into_response();
57
}
58
59
+
let result = sqlx::query!(
60
r#"
61
SELECT did, handle, email, created_at
62
FROM users
63
WHERE did = $1
64
"#,
65
+
did
66
)
67
.fetch_optional(&state.db)
68
.await;
69
70
match result {
71
Ok(Some(row)) => {
72
(
73
StatusCode::OK,
74
Json(AccountInfo {
75
+
did: row.did,
76
+
handle: row.handle,
77
+
email: Some(row.email),
78
+
indexed_at: row.created_at.to_rfc3339(),
79
invite_note: None,
80
invites_disabled: false,
81
email_confirmed_at: None,
···
135
continue;
136
}
137
138
+
let result = sqlx::query!(
139
r#"
140
SELECT did, handle, email, created_at
141
FROM users
142
WHERE did = $1
143
"#,
144
+
did
145
)
146
.fetch_optional(&state.db)
147
.await;
148
149
if let Ok(Some(row)) = result {
150
infos.push(AccountInfo {
151
+
did: row.did,
152
+
handle: row.handle,
153
+
email: Some(row.email),
154
+
indexed_at: row.created_at.to_rfc3339(),
155
invite_note: None,
156
invites_disabled: false,
157
email_confirmed_at: None,
···
191
.into_response();
192
}
193
194
+
let user = sqlx::query!("SELECT id FROM users WHERE did = $1", did)
195
.fetch_optional(&state.db)
196
.await;
197
198
+
let user_id = match user {
199
+
Ok(Some(row)) => row.id,
200
Ok(None) => {
201
return (
202
StatusCode::NOT_FOUND,
···
214
}
215
};
216
217
+
let _ = sqlx::query!("DELETE FROM sessions WHERE did = $1", did)
218
.execute(&state.db)
219
.await;
220
221
+
let _ = sqlx::query!("DELETE FROM records WHERE repo_id = $1", user_id)
222
.execute(&state.db)
223
.await;
224
225
+
let _ = sqlx::query!("DELETE FROM repos WHERE user_id = $1", user_id)
226
.execute(&state.db)
227
.await;
228
229
+
let _ = sqlx::query!("DELETE FROM blobs WHERE created_by_user = $1", user_id)
230
.execute(&state.db)
231
.await;
232
233
+
let _ = sqlx::query!("DELETE FROM user_keys WHERE user_id = $1", user_id)
234
.execute(&state.db)
235
.await;
236
237
+
let result = sqlx::query!("DELETE FROM users WHERE id = $1", user_id)
238
.execute(&state.db)
239
.await;
240
···
282
.into_response();
283
}
284
285
+
let result = sqlx::query!("UPDATE users SET email = $1 WHERE did = $2", email, account)
286
.execute(&state.db)
287
.await;
288
···
350
.into_response();
351
}
352
353
+
let existing = sqlx::query!("SELECT id FROM users WHERE handle = $1 AND did != $2", handle, did)
354
.fetch_optional(&state.db)
355
.await;
356
···
362
.into_response();
363
}
364
365
+
let result = sqlx::query!("UPDATE users SET handle = $1 WHERE did = $2", handle, did)
366
.execute(&state.db)
367
.await;
368
···
431
}
432
};
433
434
+
let result = sqlx::query!("UPDATE users SET password_hash = $1 WHERE did = $2", password_hash, did)
435
.execute(&state.db)
436
.await;
437
+11
-15
src/api/feed/timeline.rs
+11
-15
src/api/feed/timeline.rs
···
59
.unwrap_or("")
60
.replace("Bearer ", "");
61
62
-
let session = sqlx::query(
63
-
"SELECT s.did, k.key_bytes FROM sessions s JOIN users u ON s.did = u.did JOIN user_keys k ON u.id = k.user_id WHERE s.access_jwt = $1"
64
)
65
-
.bind(&token)
66
.fetch_optional(&state.db)
67
.await
68
.unwrap_or(None);
69
70
let (did, key_bytes) = match session {
71
-
Some(row) => (
72
-
row.get::<String, _>("did"),
73
-
row.get::<Vec<u8>, _>("key_bytes"),
74
-
),
75
None => {
76
return (
77
StatusCode::UNAUTHORIZED,
···
89
.into_response();
90
}
91
92
-
let user_query = sqlx::query("SELECT id FROM users WHERE did = $1")
93
-
.bind(&did)
94
.fetch_optional(&state.db)
95
.await;
96
97
-
let user_id: uuid::Uuid = match user_query {
98
-
Ok(Some(row)) => row.get("id"),
99
_ => {
100
return (
101
StatusCode::INTERNAL_SERVER_ERROR,
···
105
}
106
};
107
108
-
let follows_query = sqlx::query(
109
-
"SELECT record_cid FROM records WHERE repo_id = $1 AND collection = 'app.bsky.graph.follow'"
110
)
111
-
.bind(user_id)
112
.fetch_all(&state.db)
113
.await;
114
115
let follow_cids: Vec<String> = match follows_query {
116
-
Ok(rows) => rows.iter().map(|r| r.get("record_cid")).collect(),
117
Err(e) => {
118
error!("Failed to get follows: {:?}", e);
119
return (
···
59
.unwrap_or("")
60
.replace("Bearer ", "");
61
62
+
let session = sqlx::query!(
63
+
"SELECT s.did, k.key_bytes FROM sessions s JOIN users u ON s.did = u.did JOIN user_keys k ON u.id = k.user_id WHERE s.access_jwt = $1",
64
+
token
65
)
66
.fetch_optional(&state.db)
67
.await
68
.unwrap_or(None);
69
70
let (did, key_bytes) = match session {
71
+
Some(row) => (row.did, row.key_bytes),
72
None => {
73
return (
74
StatusCode::UNAUTHORIZED,
···
86
.into_response();
87
}
88
89
+
let user_query = sqlx::query!("SELECT id FROM users WHERE did = $1", did)
90
.fetch_optional(&state.db)
91
.await;
92
93
+
let user_id = match user_query {
94
+
Ok(Some(row)) => row.id,
95
_ => {
96
return (
97
StatusCode::INTERNAL_SERVER_ERROR,
···
101
}
102
};
103
104
+
let follows_query = sqlx::query!(
105
+
"SELECT record_cid FROM records WHERE repo_id = $1 AND collection = 'app.bsky.graph.follow'",
106
+
user_id
107
)
108
.fetch_all(&state.db)
109
.await;
110
111
let follow_cids: Vec<String> = match follows_query {
112
+
Ok(rows) => rows.iter().map(|r| r.record_cid.clone()).collect(),
113
Err(e) => {
114
error!("Failed to get follows: {:?}", e);
115
return (
+19
-29
src/api/identity/account.rs
+19
-29
src/api/identity/account.rs
···
13
use rand::rngs::OsRng;
14
use serde::{Deserialize, Serialize};
15
use serde_json::json;
16
-
use sqlx::Row;
17
use std::sync::Arc;
18
use tracing::{error, info};
19
···
82
}
83
};
84
85
-
let exists_query = sqlx::query("SELECT 1 FROM users WHERE handle = $1")
86
-
.bind(&input.handle)
87
.fetch_optional(&mut *tx)
88
.await;
89
···
108
109
if let Some(code) = &input.invite_code {
110
let invite_query =
111
-
sqlx::query("SELECT available_uses FROM invite_codes WHERE code = $1 FOR UPDATE")
112
-
.bind(code)
113
.fetch_optional(&mut *tx)
114
.await;
115
116
match invite_query {
117
Ok(Some(row)) => {
118
-
let uses: i32 = row.get("available_uses");
119
-
if uses <= 0 {
120
return (StatusCode::BAD_REQUEST, Json(json!({"error": "InvalidInviteCode", "message": "Invite code exhausted"}))).into_response();
121
}
122
123
-
let update_invite = sqlx::query(
124
"UPDATE invite_codes SET available_uses = available_uses - 1 WHERE code = $1",
125
)
126
-
.bind(code)
127
.execute(&mut *tx)
128
.await;
129
···
166
}
167
};
168
169
-
let user_insert = sqlx::query("INSERT INTO users (handle, email, did, password_hash) VALUES ($1, $2, $3, $4) RETURNING id")
170
-
.bind(&input.handle)
171
-
.bind(&input.email)
172
-
.bind(&did)
173
-
.bind(&password_hash)
174
.fetch_one(&mut *tx)
175
.await;
176
177
-
let user_id: uuid::Uuid = match user_insert {
178
-
Ok(row) => row.get("id"),
179
Err(e) => {
180
error!("Error inserting user: {:?}", e);
181
// TODO: Check for unique constraint violation on email/did specifically
···
190
let secret_key = SecretKey::random(&mut OsRng);
191
let secret_key_bytes = secret_key.to_bytes();
192
193
-
let key_insert = sqlx::query("INSERT INTO user_keys (user_id, key_bytes) VALUES ($1, $2)")
194
-
.bind(user_id)
195
-
.bind(&secret_key_bytes[..])
196
.execute(&mut *tx)
197
.await;
198
···
257
}
258
};
259
260
-
let repo_insert = sqlx::query("INSERT INTO repos (user_id, repo_root_cid) VALUES ($1, $2)")
261
-
.bind(user_id)
262
-
.bind(commit_cid.to_string())
263
.execute(&mut *tx)
264
.await;
265
···
274
275
if let Some(code) = &input.invite_code {
276
let use_insert =
277
-
sqlx::query("INSERT INTO invite_code_uses (code, used_by_user) VALUES ($1, $2)")
278
-
.bind(code)
279
-
.bind(user_id)
280
.execute(&mut *tx)
281
.await;
282
···
317
};
318
319
let session_insert =
320
-
sqlx::query("INSERT INTO sessions (access_jwt, refresh_jwt, did) VALUES ($1, $2, $3)")
321
-
.bind(&access_jwt)
322
-
.bind(&refresh_jwt)
323
-
.bind(&did)
324
.execute(&mut *tx)
325
.await;
326
···
13
use rand::rngs::OsRng;
14
use serde::{Deserialize, Serialize};
15
use serde_json::json;
16
use std::sync::Arc;
17
use tracing::{error, info};
18
···
81
}
82
};
83
84
+
let exists_query = sqlx::query!("SELECT 1 as one FROM users WHERE handle = $1", input.handle)
85
.fetch_optional(&mut *tx)
86
.await;
87
···
106
107
if let Some(code) = &input.invite_code {
108
let invite_query =
109
+
sqlx::query!("SELECT available_uses FROM invite_codes WHERE code = $1 FOR UPDATE", code)
110
.fetch_optional(&mut *tx)
111
.await;
112
113
match invite_query {
114
Ok(Some(row)) => {
115
+
if row.available_uses <= 0 {
116
return (StatusCode::BAD_REQUEST, Json(json!({"error": "InvalidInviteCode", "message": "Invite code exhausted"}))).into_response();
117
}
118
119
+
let update_invite = sqlx::query!(
120
"UPDATE invite_codes SET available_uses = available_uses - 1 WHERE code = $1",
121
+
code
122
)
123
.execute(&mut *tx)
124
.await;
125
···
162
}
163
};
164
165
+
let user_insert = sqlx::query!(
166
+
"INSERT INTO users (handle, email, did, password_hash) VALUES ($1, $2, $3, $4) RETURNING id",
167
+
input.handle,
168
+
input.email,
169
+
did,
170
+
password_hash
171
+
)
172
.fetch_one(&mut *tx)
173
.await;
174
175
+
let user_id = match user_insert {
176
+
Ok(row) => row.id,
177
Err(e) => {
178
error!("Error inserting user: {:?}", e);
179
// TODO: Check for unique constraint violation on email/did specifically
···
188
let secret_key = SecretKey::random(&mut OsRng);
189
let secret_key_bytes = secret_key.to_bytes();
190
191
+
let key_insert = sqlx::query!("INSERT INTO user_keys (user_id, key_bytes) VALUES ($1, $2)", user_id, &secret_key_bytes[..])
192
.execute(&mut *tx)
193
.await;
194
···
253
}
254
};
255
256
+
let commit_cid_str = commit_cid.to_string();
257
+
let repo_insert = sqlx::query!("INSERT INTO repos (user_id, repo_root_cid) VALUES ($1, $2)", user_id, commit_cid_str)
258
.execute(&mut *tx)
259
.await;
260
···
269
270
if let Some(code) = &input.invite_code {
271
let use_insert =
272
+
sqlx::query!("INSERT INTO invite_code_uses (code, used_by_user) VALUES ($1, $2)", code, user_id)
273
.execute(&mut *tx)
274
.await;
275
···
310
};
311
312
let session_insert =
313
+
sqlx::query!("INSERT INTO sessions (access_jwt, refresh_jwt, did) VALUES ($1, $2, $3)", access_jwt, refresh_jwt, did)
314
.execute(&mut *tx)
315
.await;
316
+14
-35
src/api/identity/did.rs
+14
-35
src/api/identity/did.rs
···
11
use reqwest;
12
use serde::Deserialize;
13
use serde_json::json;
14
-
use sqlx::Row;
15
use tracing::error;
16
17
#[derive(Deserialize)]
···
33
.into_response();
34
}
35
36
-
let user = sqlx::query("SELECT did FROM users WHERE handle = $1")
37
-
.bind(handle)
38
.fetch_optional(&state.db)
39
.await;
40
41
match user {
42
Ok(Some(row)) => {
43
-
let did: String = row.get("did");
44
-
(StatusCode::OK, Json(json!({ "did": did }))).into_response()
45
}
46
Ok(None) => (
47
StatusCode::NOT_FOUND,
···
97
pub async fn user_did_doc(State(state): State<AppState>, Path(handle): Path<String>) -> Response {
98
let hostname = std::env::var("PDS_HOSTNAME").unwrap_or_else(|_| "localhost".to_string());
99
100
-
let user = sqlx::query("SELECT id, did FROM users WHERE handle = $1")
101
-
.bind(&handle)
102
.fetch_optional(&state.db)
103
.await;
104
105
let (user_id, did) = match user {
106
-
Ok(Some(row)) => {
107
-
let id: uuid::Uuid = row.get("id");
108
-
let d: String = row.get("did");
109
-
(id, d)
110
-
}
111
Ok(None) => {
112
return (StatusCode::NOT_FOUND, Json(json!({"error": "NotFound"}))).into_response();
113
}
···
129
.into_response();
130
}
131
132
-
let key_row = sqlx::query("SELECT key_bytes FROM user_keys WHERE user_id = $1")
133
-
.bind(user_id)
134
.fetch_optional(&state.db)
135
.await;
136
137
let key_bytes: Vec<u8> = match key_row {
138
-
Ok(Some(row)) => row.get("key_bytes"),
139
_ => {
140
return (
141
StatusCode::INTERNAL_SERVER_ERROR,
···
294
.unwrap_or("")
295
.replace("Bearer ", "");
296
297
-
let session = sqlx::query(
298
r#"
299
SELECT s.did, k.key_bytes, u.handle
300
FROM sessions s
···
302
JOIN user_keys k ON u.id = k.user_id
303
WHERE s.access_jwt = $1
304
"#,
305
)
306
-
.bind(&token)
307
.fetch_optional(&state.db)
308
.await;
309
310
let (_did, key_bytes, handle) = match session {
311
-
Ok(Some(row)) => (
312
-
row.get::<String, _>("did"),
313
-
row.get::<Vec<u8>, _>("key_bytes"),
314
-
row.get::<String, _>("handle"),
315
-
),
316
Ok(None) => {
317
return (
318
StatusCode::UNAUTHORIZED,
···
404
.unwrap_or("")
405
.replace("Bearer ", "");
406
407
-
let session = sqlx::query(
408
r#"
409
SELECT s.did, k.key_bytes, u.id as user_id
410
FROM sessions s
···
412
JOIN user_keys k ON u.id = k.user_id
413
WHERE s.access_jwt = $1
414
"#,
415
)
416
-
.bind(&token)
417
.fetch_optional(&state.db)
418
.await;
419
420
let (_did, key_bytes, user_id) = match session {
421
-
Ok(Some(row)) => (
422
-
row.get::<String, _>("did"),
423
-
row.get::<Vec<u8>, _>("key_bytes"),
424
-
row.get::<uuid::Uuid, _>("user_id"),
425
-
),
426
Ok(None) => {
427
return (
428
StatusCode::UNAUTHORIZED,
···
468
.into_response();
469
}
470
471
-
let existing = sqlx::query("SELECT id FROM users WHERE handle = $1 AND id != $2")
472
-
.bind(new_handle)
473
-
.bind(user_id)
474
.fetch_optional(&state.db)
475
.await;
476
···
482
.into_response();
483
}
484
485
-
let result = sqlx::query("UPDATE users SET handle = $1 WHERE id = $2")
486
-
.bind(new_handle)
487
-
.bind(user_id)
488
.execute(&state.db)
489
.await;
490
···
11
use reqwest;
12
use serde::Deserialize;
13
use serde_json::json;
14
use tracing::error;
15
16
#[derive(Deserialize)]
···
32
.into_response();
33
}
34
35
+
let user = sqlx::query!("SELECT did FROM users WHERE handle = $1", handle)
36
.fetch_optional(&state.db)
37
.await;
38
39
match user {
40
Ok(Some(row)) => {
41
+
(StatusCode::OK, Json(json!({ "did": row.did }))).into_response()
42
}
43
Ok(None) => (
44
StatusCode::NOT_FOUND,
···
94
pub async fn user_did_doc(State(state): State<AppState>, Path(handle): Path<String>) -> Response {
95
let hostname = std::env::var("PDS_HOSTNAME").unwrap_or_else(|_| "localhost".to_string());
96
97
+
let user = sqlx::query!("SELECT id, did FROM users WHERE handle = $1", handle)
98
.fetch_optional(&state.db)
99
.await;
100
101
let (user_id, did) = match user {
102
+
Ok(Some(row)) => (row.id, row.did),
103
Ok(None) => {
104
return (StatusCode::NOT_FOUND, Json(json!({"error": "NotFound"}))).into_response();
105
}
···
121
.into_response();
122
}
123
124
+
let key_row = sqlx::query!("SELECT key_bytes FROM user_keys WHERE user_id = $1", user_id)
125
.fetch_optional(&state.db)
126
.await;
127
128
let key_bytes: Vec<u8> = match key_row {
129
+
Ok(Some(row)) => row.key_bytes,
130
_ => {
131
return (
132
StatusCode::INTERNAL_SERVER_ERROR,
···
285
.unwrap_or("")
286
.replace("Bearer ", "");
287
288
+
let session = sqlx::query!(
289
r#"
290
SELECT s.did, k.key_bytes, u.handle
291
FROM sessions s
···
293
JOIN user_keys k ON u.id = k.user_id
294
WHERE s.access_jwt = $1
295
"#,
296
+
token
297
)
298
.fetch_optional(&state.db)
299
.await;
300
301
let (_did, key_bytes, handle) = match session {
302
+
Ok(Some(row)) => (row.did, row.key_bytes, row.handle),
303
Ok(None) => {
304
return (
305
StatusCode::UNAUTHORIZED,
···
391
.unwrap_or("")
392
.replace("Bearer ", "");
393
394
+
let session = sqlx::query!(
395
r#"
396
SELECT s.did, k.key_bytes, u.id as user_id
397
FROM sessions s
···
399
JOIN user_keys k ON u.id = k.user_id
400
WHERE s.access_jwt = $1
401
"#,
402
+
token
403
)
404
.fetch_optional(&state.db)
405
.await;
406
407
let (_did, key_bytes, user_id) = match session {
408
+
Ok(Some(row)) => (row.did, row.key_bytes, row.user_id),
409
Ok(None) => {
410
return (
411
StatusCode::UNAUTHORIZED,
···
451
.into_response();
452
}
453
454
+
let existing = sqlx::query!("SELECT id FROM users WHERE handle = $1 AND id != $2", new_handle, user_id)
455
.fetch_optional(&state.db)
456
.await;
457
···
463
.into_response();
464
}
465
466
+
let result = sqlx::query!("UPDATE users SET handle = $1 WHERE id = $2", new_handle, user_id)
467
.execute(&state.db)
468
.await;
469
+12
-15
src/api/moderation/mod.rs
+12
-15
src/api/moderation/mod.rs
···
7
};
8
use serde::{Deserialize, Serialize};
9
use serde_json::{Value, json};
10
-
use sqlx::Row;
11
use tracing::error;
12
13
#[derive(Deserialize)]
···
49
.unwrap_or("")
50
.replace("Bearer ", "");
51
52
-
let session = sqlx::query(
53
r#"
54
SELECT s.did, k.key_bytes
55
FROM sessions s
···
57
JOIN user_keys k ON u.id = k.user_id
58
WHERE s.access_jwt = $1
59
"#,
60
)
61
-
.bind(&token)
62
.fetch_optional(&state.db)
63
.await;
64
65
let (did, key_bytes) = match session {
66
-
Ok(Some(row)) => (
67
-
row.get::<String, _>("did"),
68
-
row.get::<Vec<u8>, _>("key_bytes"),
69
-
),
70
Ok(None) => {
71
return (
72
StatusCode::UNAUTHORIZED,
···
113
let created_at = chrono::Utc::now();
114
let report_id = created_at.timestamp_millis();
115
116
-
let insert = sqlx::query(
117
-
"INSERT INTO reports (id, reason_type, reason, subject_json, reported_by_did, created_at) VALUES ($1, $2, $3, $4, $5, $6)"
118
)
119
-
.bind(report_id)
120
-
.bind(&input.reason_type)
121
-
.bind(&input.reason)
122
-
.bind(json!(input.subject))
123
-
.bind(&did)
124
-
.bind(created_at)
125
.execute(&state.db)
126
.await;
127
···
7
};
8
use serde::{Deserialize, Serialize};
9
use serde_json::{Value, json};
10
use tracing::error;
11
12
#[derive(Deserialize)]
···
48
.unwrap_or("")
49
.replace("Bearer ", "");
50
51
+
let session = sqlx::query!(
52
r#"
53
SELECT s.did, k.key_bytes
54
FROM sessions s
···
56
JOIN user_keys k ON u.id = k.user_id
57
WHERE s.access_jwt = $1
58
"#,
59
+
token
60
)
61
.fetch_optional(&state.db)
62
.await;
63
64
let (did, key_bytes) = match session {
65
+
Ok(Some(row)) => (row.did, row.key_bytes),
66
Ok(None) => {
67
return (
68
StatusCode::UNAUTHORIZED,
···
109
let created_at = chrono::Utc::now();
110
let report_id = created_at.timestamp_millis();
111
112
+
let subject_json = json!(input.subject);
113
+
let insert = sqlx::query!(
114
+
"INSERT INTO reports (id, reason_type, reason, subject_json, reported_by_did, created_at) VALUES ($1, $2, $3, $4, $5, $6)",
115
+
report_id,
116
+
input.reason_type,
117
+
input.reason,
118
+
subject_json,
119
+
did,
120
+
created_at
121
)
122
.execute(&state.db)
123
.await;
124
+2
-5
src/api/proxy.rs
+2
-5
src/api/proxy.rs
···
6
response::{IntoResponse, Response},
7
};
8
use reqwest::Client;
9
-
use sqlx::Row;
10
use std::collections::HashMap;
11
use tracing::{error, info};
12
···
48
if let Ok(token) = auth_val.to_str() {
49
let token = token.replace("Bearer ", "");
50
if let Ok(did) = crate::auth::get_did_from_token(&token) {
51
-
let key_row = sqlx::query("SELECT k.key_bytes FROM user_keys k JOIN users u ON k.user_id = u.id WHERE u.did = $1")
52
-
.bind(&did)
53
.fetch_optional(&state.db)
54
.await;
55
56
if let Ok(Some(row)) = key_row {
57
-
let key_bytes: Vec<u8> = row.get("key_bytes");
58
if let Ok(new_token) =
59
-
crate::auth::create_service_token(&did, aud, &method, &key_bytes)
60
{
61
if let Ok(val) =
62
axum::http::HeaderValue::from_str(&format!("Bearer {}", new_token))
···
6
response::{IntoResponse, Response},
7
};
8
use reqwest::Client;
9
use std::collections::HashMap;
10
use tracing::{error, info};
11
···
47
if let Ok(token) = auth_val.to_str() {
48
let token = token.replace("Bearer ", "");
49
if let Ok(did) = crate::auth::get_did_from_token(&token) {
50
+
let key_row = sqlx::query!("SELECT k.key_bytes FROM user_keys k JOIN users u ON k.user_id = u.id WHERE u.did = $1", did)
51
.fetch_optional(&state.db)
52
.await;
53
54
if let Ok(Some(row)) = key_row {
55
if let Ok(new_token) =
56
+
crate::auth::create_service_token(&did, aud, &method, &row.key_bytes)
57
{
58
if let Ok(val) =
59
axum::http::HeaderValue::from_str(&format!("Bearer {}", new_token))
+31
-42
src/api/repo/blob.rs
+31
-42
src/api/repo/blob.rs
···
12
use serde::{Deserialize, Serialize};
13
use serde_json::json;
14
use sha2::{Digest, Sha256};
15
-
use sqlx::Row;
16
use std::str::FromStr;
17
use tracing::error;
18
···
35
.unwrap_or("")
36
.replace("Bearer ", "");
37
38
-
let session = sqlx::query(
39
-
"SELECT s.did, k.key_bytes FROM sessions s JOIN users u ON s.did = u.did JOIN user_keys k ON u.id = k.user_id WHERE s.access_jwt = $1"
40
)
41
-
.bind(&token)
42
.fetch_optional(&state.db)
43
.await
44
.unwrap_or(None);
45
46
let (did, key_bytes) = match session {
47
-
Some(row) => (
48
-
row.get::<String, _>("did"),
49
-
row.get::<Vec<u8>, _>("key_bytes"),
50
-
),
51
None => {
52
return (
53
StatusCode::UNAUTHORIZED,
···
92
.into_response();
93
}
94
95
-
let user_query = sqlx::query("SELECT id FROM users WHERE did = $1")
96
-
.bind(&did)
97
.fetch_optional(&state.db)
98
.await;
99
100
-
let user_id: uuid::Uuid = match user_query {
101
-
Ok(Some(row)) => row.get("id"),
102
_ => {
103
return (
104
StatusCode::INTERNAL_SERVER_ERROR,
···
108
}
109
};
110
111
-
let insert = sqlx::query(
112
-
"INSERT INTO blobs (cid, mime_type, size_bytes, created_by_user, storage_key) VALUES ($1, $2, $3, $4, $5) ON CONFLICT (cid) DO NOTHING"
113
)
114
-
.bind(&cid_str)
115
-
.bind(&mime_type)
116
-
.bind(size)
117
-
.bind(user_id)
118
-
.bind(&storage_key)
119
.execute(&state.db)
120
.await;
121
···
202
.unwrap_or("")
203
.replace("Bearer ", "");
204
205
-
let session = sqlx::query(
206
-
"SELECT s.did, k.key_bytes FROM sessions s JOIN users u ON s.did = u.did JOIN user_keys k ON u.id = k.user_id WHERE s.access_jwt = $1"
207
)
208
-
.bind(&token)
209
.fetch_optional(&state.db)
210
.await
211
.unwrap_or(None);
212
213
let (did, key_bytes) = match session {
214
-
Some(row) => (
215
-
row.get::<String, _>("did"),
216
-
row.get::<Vec<u8>, _>("key_bytes"),
217
-
),
218
None => {
219
return (
220
StatusCode::UNAUTHORIZED,
···
232
.into_response();
233
}
234
235
-
let user_query = sqlx::query("SELECT id FROM users WHERE did = $1")
236
-
.bind(&did)
237
.fetch_optional(&state.db)
238
.await;
239
240
-
let user_id: uuid::Uuid = match user_query {
241
-
Ok(Some(row)) => row.get("id"),
242
_ => {
243
return (
244
StatusCode::INTERNAL_SERVER_ERROR,
···
257
(String::new(), String::new())
258
};
259
260
-
let records_query = sqlx::query(
261
-
"SELECT collection, rkey, record_cid FROM records WHERE repo_id = $1 AND (collection, rkey) > ($2, $3) ORDER BY collection, rkey LIMIT $4"
262
)
263
-
.bind(user_id)
264
-
.bind(cursor_collection)
265
-
.bind(cursor_rkey)
266
-
.bind(limit)
267
.fetch_all(&state.db)
268
.await;
269
···
283
let mut last_cursor = None;
284
285
for row in &records {
286
-
let collection: String = row.get("collection");
287
-
let rkey: String = row.get("rkey");
288
-
let record_cid_str: String = row.get("record_cid");
289
290
last_cursor = Some(format!("{}|{}", collection, rkey));
291
···
308
find_blobs(&record_val, &mut blobs);
309
310
for blob_cid_str in blobs {
311
-
let exists = sqlx::query("SELECT 1 FROM blobs WHERE cid = $1 AND created_by_user = $2")
312
-
.bind(&blob_cid_str)
313
-
.bind(user_id)
314
.fetch_optional(&state.db)
315
.await;
316
···
12
use serde::{Deserialize, Serialize};
13
use serde_json::json;
14
use sha2::{Digest, Sha256};
15
use std::str::FromStr;
16
use tracing::error;
17
···
34
.unwrap_or("")
35
.replace("Bearer ", "");
36
37
+
let session = sqlx::query!(
38
+
"SELECT s.did, k.key_bytes FROM sessions s JOIN users u ON s.did = u.did JOIN user_keys k ON u.id = k.user_id WHERE s.access_jwt = $1",
39
+
token
40
)
41
.fetch_optional(&state.db)
42
.await
43
.unwrap_or(None);
44
45
let (did, key_bytes) = match session {
46
+
Some(row) => (row.did, row.key_bytes),
47
None => {
48
return (
49
StatusCode::UNAUTHORIZED,
···
88
.into_response();
89
}
90
91
+
let user_query = sqlx::query!("SELECT id FROM users WHERE did = $1", did)
92
.fetch_optional(&state.db)
93
.await;
94
95
+
let user_id = match user_query {
96
+
Ok(Some(row)) => row.id,
97
_ => {
98
return (
99
StatusCode::INTERNAL_SERVER_ERROR,
···
103
}
104
};
105
106
+
let insert = sqlx::query!(
107
+
"INSERT INTO blobs (cid, mime_type, size_bytes, created_by_user, storage_key) VALUES ($1, $2, $3, $4, $5) ON CONFLICT (cid) DO NOTHING",
108
+
cid_str,
109
+
mime_type,
110
+
size,
111
+
user_id,
112
+
storage_key
113
)
114
.execute(&state.db)
115
.await;
116
···
197
.unwrap_or("")
198
.replace("Bearer ", "");
199
200
+
let session = sqlx::query!(
201
+
"SELECT s.did, k.key_bytes FROM sessions s JOIN users u ON s.did = u.did JOIN user_keys k ON u.id = k.user_id WHERE s.access_jwt = $1",
202
+
token
203
)
204
.fetch_optional(&state.db)
205
.await
206
.unwrap_or(None);
207
208
let (did, key_bytes) = match session {
209
+
Some(row) => (row.did, row.key_bytes),
210
None => {
211
return (
212
StatusCode::UNAUTHORIZED,
···
224
.into_response();
225
}
226
227
+
let user_query = sqlx::query!("SELECT id FROM users WHERE did = $1", did)
228
.fetch_optional(&state.db)
229
.await;
230
231
+
let user_id = match user_query {
232
+
Ok(Some(row)) => row.id,
233
_ => {
234
return (
235
StatusCode::INTERNAL_SERVER_ERROR,
···
248
(String::new(), String::new())
249
};
250
251
+
let records_query = sqlx::query!(
252
+
"SELECT collection, rkey, record_cid FROM records WHERE repo_id = $1 AND (collection, rkey) > ($2, $3) ORDER BY collection, rkey LIMIT $4",
253
+
user_id,
254
+
cursor_collection,
255
+
cursor_rkey,
256
+
limit
257
)
258
.fetch_all(&state.db)
259
.await;
260
···
274
let mut last_cursor = None;
275
276
for row in &records {
277
+
let collection = &row.collection;
278
+
let rkey = &row.rkey;
279
+
let record_cid_str = &row.record_cid;
280
281
last_cursor = Some(format!("{}|{}", collection, rkey));
282
···
299
find_blobs(&record_val, &mut blobs);
300
301
for blob_cid_str in blobs {
302
+
let exists = sqlx::query!("SELECT 1 as one FROM blobs WHERE cid = $1 AND created_by_user = $2", blob_cid_str, user_id)
303
.fetch_optional(&state.db)
304
.await;
305
+1
-1
src/api/server/meta.rs
+1
-1
src/api/server/meta.rs
+81
-127
src/api/server/session.rs
+81
-127
src/api/server/session.rs
···
8
use bcrypt::verify;
9
use serde::{Deserialize, Serialize};
10
use serde_json::json;
11
-
use sqlx::Row;
12
use tracing::{error, info, warn};
13
14
#[derive(Deserialize)]
···
43
.unwrap_or("")
44
.replace("Bearer ", "");
45
46
-
let session = sqlx::query(
47
r#"
48
SELECT s.did, k.key_bytes
49
FROM sessions s
···
51
JOIN user_keys k ON u.id = k.user_id
52
WHERE s.access_jwt = $1
53
"#,
54
)
55
-
.bind(&token)
56
.fetch_optional(&state.db)
57
.await;
58
59
let (did, key_bytes) = match session {
60
-
Ok(Some(row)) => (
61
-
row.get::<String, _>("did"),
62
-
row.get::<Vec<u8>, _>("key_bytes"),
63
-
),
64
Ok(None) => {
65
return (
66
StatusCode::UNAUTHORIZED,
···
125
) -> Response {
126
info!("create_session: identifier='{}'", input.identifier);
127
128
-
let user_row = sqlx::query("SELECT u.id, u.did, u.handle, u.password_hash, k.key_bytes FROM users u JOIN user_keys k ON u.id = k.user_id WHERE u.handle = $1 OR u.email = $1")
129
-
.bind(&input.identifier)
130
.fetch_optional(&state.db)
131
.await;
132
133
match user_row {
134
Ok(Some(row)) => {
135
-
let user_id: uuid::Uuid = row.get("id");
136
-
let stored_hash: String = row.get("password_hash");
137
-
let did: String = row.get("did");
138
-
let handle: String = row.get("handle");
139
-
let key_bytes: Vec<u8> = row.get("key_bytes");
140
141
-
let password_valid = if verify(&input.password, &stored_hash).unwrap_or(false) {
142
true
143
} else {
144
-
let app_pass_rows = sqlx::query("SELECT password_hash FROM app_passwords WHERE user_id = $1")
145
-
.bind(user_id)
146
.fetch_all(&state.db)
147
.await
148
.unwrap_or_default();
149
150
app_pass_rows.iter().any(|row| {
151
-
let hash: String = row.get("password_hash");
152
-
verify(&input.password, &hash).unwrap_or(false)
153
})
154
};
155
···
178
}
179
};
180
181
-
let session_insert = sqlx::query(
182
"INSERT INTO sessions (access_jwt, refresh_jwt, did) VALUES ($1, $2, $3)",
183
)
184
-
.bind(&access_jwt)
185
-
.bind(&refresh_jwt)
186
-
.bind(&did)
187
.execute(&state.db)
188
.await;
189
···
194
Json(CreateSessionOutput {
195
access_jwt,
196
refresh_jwt,
197
-
handle,
198
-
did,
199
}),
200
)
201
.into_response();
···
255
.unwrap_or("")
256
.replace("Bearer ", "");
257
258
-
let result = sqlx::query(
259
r#"
260
SELECT u.handle, u.did, u.email, k.key_bytes
261
FROM sessions s
···
263
JOIN user_keys k ON u.id = k.user_id
264
WHERE s.access_jwt = $1
265
"#,
266
)
267
-
.bind(&token)
268
.fetch_optional(&state.db)
269
.await;
270
271
match result {
272
Ok(Some(row)) => {
273
-
let handle: String = row.get("handle");
274
-
let did: String = row.get("did");
275
-
let email: String = row.get("email");
276
-
let key_bytes: Vec<u8> = row.get("key_bytes");
277
-
278
-
if let Err(_) = crate::auth::verify_token(&token, &key_bytes) {
279
return (StatusCode::UNAUTHORIZED, Json(json!({"error": "AuthenticationFailed", "message": "Invalid token signature"}))).into_response();
280
}
281
282
return (
283
StatusCode::OK,
284
Json(json!({
285
-
"handle": handle,
286
-
"did": did,
287
-
"email": email,
288
"didDoc": {}
289
})),
290
)
···
327
.unwrap_or("")
328
.replace("Bearer ", "");
329
330
-
let result = sqlx::query("DELETE FROM sessions WHERE access_jwt = $1")
331
-
.bind(token)
332
.execute(&state.db)
333
.await;
334
···
369
.unwrap_or("")
370
.replace("Bearer ", "");
371
372
-
let session = sqlx::query(
373
-
"SELECT s.did, k.key_bytes FROM sessions s JOIN users u ON s.did = u.did JOIN user_keys k ON u.id = k.user_id WHERE s.refresh_jwt = $1"
374
)
375
-
.bind(&refresh_token)
376
.fetch_optional(&state.db)
377
.await;
378
379
match session {
380
Ok(Some(session_row)) => {
381
-
let did: String = session_row.get("did");
382
-
let key_bytes: Vec<u8> = session_row.get("key_bytes");
383
384
if let Err(_) = crate::auth::verify_token(&refresh_token, &key_bytes) {
385
return (StatusCode::UNAUTHORIZED, Json(json!({"error": "AuthenticationFailed", "message": "Invalid refresh token signature"}))).into_response();
···
408
}
409
};
410
411
-
let update = sqlx::query(
412
"UPDATE sessions SET access_jwt = $1, refresh_jwt = $2 WHERE refresh_jwt = $3",
413
)
414
-
.bind(&new_access_jwt)
415
-
.bind(&new_refresh_jwt)
416
-
.bind(&refresh_token)
417
.execute(&state.db)
418
.await;
419
420
match update {
421
Ok(_) => {
422
-
let user = sqlx::query("SELECT handle FROM users WHERE did = $1")
423
-
.bind(&did)
424
.fetch_optional(&state.db)
425
.await;
426
427
match user {
428
Ok(Some(u)) => {
429
-
let handle: String = u.get("handle");
430
return (
431
StatusCode::OK,
432
Json(json!({
433
"accessJwt": new_access_jwt,
434
"refreshJwt": new_refresh_jwt,
435
-
"handle": handle,
436
"did": did
437
})),
438
)
···
517
.unwrap_or("")
518
.replace("Bearer ", "");
519
520
-
let session = sqlx::query(
521
r#"
522
SELECT s.did, k.key_bytes, u.id as user_id
523
FROM sessions s
···
525
JOIN user_keys k ON u.id = k.user_id
526
WHERE s.access_jwt = $1
527
"#,
528
)
529
-
.bind(&token)
530
.fetch_optional(&state.db)
531
.await;
532
533
let (did, key_bytes, user_id) = match session {
534
-
Ok(Some(row)) => (
535
-
row.get::<String, _>("did"),
536
-
row.get::<Vec<u8>, _>("key_bytes"),
537
-
row.get::<uuid::Uuid, _>("user_id"),
538
-
),
539
Ok(None) => {
540
return (
541
StatusCode::UNAUTHORIZED,
···
561
.into_response();
562
}
563
564
-
let user_status = sqlx::query("SELECT deactivated_at FROM users WHERE did = $1")
565
-
.bind(&did)
566
.fetch_optional(&state.db)
567
.await;
568
569
-
let deactivated_at: Option<chrono::DateTime<chrono::Utc>> = match user_status {
570
-
Ok(Some(row)) => row.get("deactivated_at"),
571
_ => None,
572
};
573
574
-
let repo_result = sqlx::query("SELECT repo_root_cid FROM repos WHERE user_id = $1")
575
-
.bind(user_id)
576
.fetch_optional(&state.db)
577
.await;
578
579
let repo_commit = match repo_result {
580
-
Ok(Some(row)) => row.get::<String, _>("repo_root_cid"),
581
_ => String::new(),
582
};
583
584
-
let record_count: i64 = sqlx::query_scalar("SELECT COUNT(*) FROM records WHERE repo_id = $1")
585
-
.bind(user_id)
586
.fetch_one(&state.db)
587
.await
588
.unwrap_or(0);
589
590
let blob_count: i64 =
591
-
sqlx::query_scalar("SELECT COUNT(*) FROM blobs WHERE created_by_user = $1")
592
-
.bind(user_id)
593
.fetch_one(&state.db)
594
.await
595
.unwrap_or(0);
596
597
let valid_did = did.starts_with("did:");
···
632
.unwrap_or("")
633
.replace("Bearer ", "");
634
635
-
let session = sqlx::query(
636
r#"
637
SELECT s.did, k.key_bytes
638
FROM sessions s
···
640
JOIN user_keys k ON u.id = k.user_id
641
WHERE s.access_jwt = $1
642
"#,
643
)
644
-
.bind(&token)
645
.fetch_optional(&state.db)
646
.await;
647
648
let (did, key_bytes) = match session {
649
-
Ok(Some(row)) => (
650
-
row.get::<String, _>("did"),
651
-
row.get::<Vec<u8>, _>("key_bytes"),
652
-
),
653
Ok(None) => {
654
return (
655
StatusCode::UNAUTHORIZED,
···
675
.into_response();
676
}
677
678
-
let result = sqlx::query("UPDATE users SET deactivated_at = NULL WHERE did = $1")
679
-
.bind(&did)
680
.execute(&state.db)
681
.await;
682
···
719
.unwrap_or("")
720
.replace("Bearer ", "");
721
722
-
let session = sqlx::query(
723
r#"
724
SELECT s.did, k.key_bytes
725
FROM sessions s
···
727
JOIN user_keys k ON u.id = k.user_id
728
WHERE s.access_jwt = $1
729
"#,
730
)
731
-
.bind(&token)
732
.fetch_optional(&state.db)
733
.await;
734
735
let (did, key_bytes) = match session {
736
-
Ok(Some(row)) => (
737
-
row.get::<String, _>("did"),
738
-
row.get::<Vec<u8>, _>("key_bytes"),
739
-
),
740
Ok(None) => {
741
return (
742
StatusCode::UNAUTHORIZED,
···
762
.into_response();
763
}
764
765
-
let result = sqlx::query("UPDATE users SET deactivated_at = NOW() WHERE did = $1")
766
-
.bind(&did)
767
.execute(&state.db)
768
.await;
769
···
812
.unwrap_or("")
813
.replace("Bearer ", "");
814
815
-
let session = sqlx::query(
816
r#"
817
SELECT s.did, k.key_bytes, u.id as user_id
818
FROM sessions s
···
820
JOIN user_keys k ON u.id = k.user_id
821
WHERE s.access_jwt = $1
822
"#,
823
)
824
-
.bind(&token)
825
.fetch_optional(&state.db)
826
.await;
827
828
let (_did, key_bytes, user_id) = match session {
829
-
Ok(Some(row)) => (
830
-
row.get::<String, _>("did"),
831
-
row.get::<Vec<u8>, _>("key_bytes"),
832
-
row.get::<uuid::Uuid, _>("user_id"),
833
-
),
834
Ok(None) => {
835
return (
836
StatusCode::UNAUTHORIZED,
···
856
.into_response();
857
}
858
859
-
let result = sqlx::query("SELECT name, created_at, privileged FROM app_passwords WHERE user_id = $1 ORDER BY created_at DESC")
860
-
.bind(user_id)
861
.fetch_all(&state.db)
862
.await;
863
···
866
let passwords: Vec<AppPassword> = rows
867
.iter()
868
.map(|row| {
869
-
let name: String = row.get("name");
870
-
let created_at: chrono::DateTime<chrono::Utc> = row.get("created_at");
871
-
let privileged: bool = row.get("privileged");
872
AppPassword {
873
-
name,
874
-
created_at: created_at.to_rfc3339(),
875
-
privileged,
876
}
877
})
878
.collect();
···
925
.unwrap_or("")
926
.replace("Bearer ", "");
927
928
-
let session = sqlx::query(
929
r#"
930
SELECT s.did, k.key_bytes, u.id as user_id
931
FROM sessions s
···
933
JOIN user_keys k ON u.id = k.user_id
934
WHERE s.access_jwt = $1
935
"#,
936
)
937
-
.bind(&token)
938
.fetch_optional(&state.db)
939
.await;
940
941
let (_did, key_bytes, user_id) = match session {
942
-
Ok(Some(row)) => (
943
-
row.get::<String, _>("did"),
944
-
row.get::<Vec<u8>, _>("key_bytes"),
945
-
row.get::<uuid::Uuid, _>("user_id"),
946
-
),
947
Ok(None) => {
948
return (
949
StatusCode::UNAUTHORIZED,
···
978
.into_response();
979
}
980
981
-
let existing = sqlx::query("SELECT id FROM app_passwords WHERE user_id = $1 AND name = $2")
982
-
.bind(user_id)
983
-
.bind(name)
984
.fetch_optional(&state.db)
985
.await;
986
···
1017
let privileged = input.privileged.unwrap_or(false);
1018
let created_at = chrono::Utc::now();
1019
1020
-
let result = sqlx::query(
1021
-
"INSERT INTO app_passwords (user_id, name, password_hash, created_at, privileged) VALUES ($1, $2, $3, $4, $5)"
1022
)
1023
-
.bind(user_id)
1024
-
.bind(name)
1025
-
.bind(&password_hash)
1026
-
.bind(created_at)
1027
-
.bind(privileged)
1028
.execute(&state.db)
1029
.await;
1030
···
1075
.unwrap_or("")
1076
.replace("Bearer ", "");
1077
1078
-
let session = sqlx::query(
1079
r#"
1080
SELECT s.did, k.key_bytes, u.id as user_id
1081
FROM sessions s
···
1083
JOIN user_keys k ON u.id = k.user_id
1084
WHERE s.access_jwt = $1
1085
"#,
1086
)
1087
-
.bind(&token)
1088
.fetch_optional(&state.db)
1089
.await;
1090
1091
let (_did, key_bytes, user_id) = match session {
1092
-
Ok(Some(row)) => (
1093
-
row.get::<String, _>("did"),
1094
-
row.get::<Vec<u8>, _>("key_bytes"),
1095
-
row.get::<uuid::Uuid, _>("user_id"),
1096
-
),
1097
Ok(None) => {
1098
return (
1099
StatusCode::UNAUTHORIZED,
···
1128
.into_response();
1129
}
1130
1131
-
let result = sqlx::query("DELETE FROM app_passwords WHERE user_id = $1 AND name = $2")
1132
-
.bind(user_id)
1133
-
.bind(name)
1134
.execute(&state.db)
1135
.await;
1136
···
8
use bcrypt::verify;
9
use serde::{Deserialize, Serialize};
10
use serde_json::json;
11
use tracing::{error, info, warn};
12
13
#[derive(Deserialize)]
···
42
.unwrap_or("")
43
.replace("Bearer ", "");
44
45
+
let session = sqlx::query!(
46
r#"
47
SELECT s.did, k.key_bytes
48
FROM sessions s
···
50
JOIN user_keys k ON u.id = k.user_id
51
WHERE s.access_jwt = $1
52
"#,
53
+
token
54
)
55
.fetch_optional(&state.db)
56
.await;
57
58
let (did, key_bytes) = match session {
59
+
Ok(Some(row)) => (row.did, row.key_bytes),
60
Ok(None) => {
61
return (
62
StatusCode::UNAUTHORIZED,
···
121
) -> Response {
122
info!("create_session: identifier='{}'", input.identifier);
123
124
+
let user_row = sqlx::query!(
125
+
"SELECT u.id, u.did, u.handle, u.password_hash, k.key_bytes FROM users u JOIN user_keys k ON u.id = k.user_id WHERE u.handle = $1 OR u.email = $1",
126
+
input.identifier
127
+
)
128
.fetch_optional(&state.db)
129
.await;
130
131
match user_row {
132
Ok(Some(row)) => {
133
+
let user_id = row.id;
134
+
let stored_hash = &row.password_hash;
135
+
let did = &row.did;
136
+
let handle = &row.handle;
137
+
let key_bytes = &row.key_bytes;
138
139
+
let password_valid = if verify(&input.password, stored_hash).unwrap_or(false) {
140
true
141
} else {
142
+
let app_pass_rows = sqlx::query!("SELECT password_hash FROM app_passwords WHERE user_id = $1", user_id)
143
.fetch_all(&state.db)
144
.await
145
.unwrap_or_default();
146
147
app_pass_rows.iter().any(|row| {
148
+
verify(&input.password, &row.password_hash).unwrap_or(false)
149
})
150
};
151
···
174
}
175
};
176
177
+
let session_insert = sqlx::query!(
178
"INSERT INTO sessions (access_jwt, refresh_jwt, did) VALUES ($1, $2, $3)",
179
+
access_jwt,
180
+
refresh_jwt,
181
+
did
182
)
183
.execute(&state.db)
184
.await;
185
···
190
Json(CreateSessionOutput {
191
access_jwt,
192
refresh_jwt,
193
+
handle: handle.clone(),
194
+
did: did.clone(),
195
}),
196
)
197
.into_response();
···
251
.unwrap_or("")
252
.replace("Bearer ", "");
253
254
+
let result = sqlx::query!(
255
r#"
256
SELECT u.handle, u.did, u.email, k.key_bytes
257
FROM sessions s
···
259
JOIN user_keys k ON u.id = k.user_id
260
WHERE s.access_jwt = $1
261
"#,
262
+
token
263
)
264
.fetch_optional(&state.db)
265
.await;
266
267
match result {
268
Ok(Some(row)) => {
269
+
if let Err(_) = crate::auth::verify_token(&token, &row.key_bytes) {
270
return (StatusCode::UNAUTHORIZED, Json(json!({"error": "AuthenticationFailed", "message": "Invalid token signature"}))).into_response();
271
}
272
273
return (
274
StatusCode::OK,
275
Json(json!({
276
+
"handle": row.handle,
277
+
"did": row.did,
278
+
"email": row.email,
279
"didDoc": {}
280
})),
281
)
···
318
.unwrap_or("")
319
.replace("Bearer ", "");
320
321
+
let result = sqlx::query!("DELETE FROM sessions WHERE access_jwt = $1", token)
322
.execute(&state.db)
323
.await;
324
···
359
.unwrap_or("")
360
.replace("Bearer ", "");
361
362
+
let session = sqlx::query!(
363
+
"SELECT s.did, k.key_bytes FROM sessions s JOIN users u ON s.did = u.did JOIN user_keys k ON u.id = k.user_id WHERE s.refresh_jwt = $1",
364
+
refresh_token
365
)
366
.fetch_optional(&state.db)
367
.await;
368
369
match session {
370
Ok(Some(session_row)) => {
371
+
let did = &session_row.did;
372
+
let key_bytes = &session_row.key_bytes;
373
374
if let Err(_) = crate::auth::verify_token(&refresh_token, &key_bytes) {
375
return (StatusCode::UNAUTHORIZED, Json(json!({"error": "AuthenticationFailed", "message": "Invalid refresh token signature"}))).into_response();
···
398
}
399
};
400
401
+
let update = sqlx::query!(
402
"UPDATE sessions SET access_jwt = $1, refresh_jwt = $2 WHERE refresh_jwt = $3",
403
+
new_access_jwt,
404
+
new_refresh_jwt,
405
+
refresh_token
406
)
407
.execute(&state.db)
408
.await;
409
410
match update {
411
Ok(_) => {
412
+
let user = sqlx::query!("SELECT handle FROM users WHERE did = $1", did)
413
.fetch_optional(&state.db)
414
.await;
415
416
match user {
417
Ok(Some(u)) => {
418
return (
419
StatusCode::OK,
420
Json(json!({
421
"accessJwt": new_access_jwt,
422
"refreshJwt": new_refresh_jwt,
423
+
"handle": u.handle,
424
"did": did
425
})),
426
)
···
505
.unwrap_or("")
506
.replace("Bearer ", "");
507
508
+
let session = sqlx::query!(
509
r#"
510
SELECT s.did, k.key_bytes, u.id as user_id
511
FROM sessions s
···
513
JOIN user_keys k ON u.id = k.user_id
514
WHERE s.access_jwt = $1
515
"#,
516
+
token
517
)
518
.fetch_optional(&state.db)
519
.await;
520
521
let (did, key_bytes, user_id) = match session {
522
+
Ok(Some(row)) => (row.did, row.key_bytes, row.user_id),
523
Ok(None) => {
524
return (
525
StatusCode::UNAUTHORIZED,
···
545
.into_response();
546
}
547
548
+
let user_status = sqlx::query!("SELECT deactivated_at FROM users WHERE did = $1", did)
549
.fetch_optional(&state.db)
550
.await;
551
552
+
let deactivated_at = match user_status {
553
+
Ok(Some(row)) => row.deactivated_at,
554
_ => None,
555
};
556
557
+
let repo_result = sqlx::query!("SELECT repo_root_cid FROM repos WHERE user_id = $1", user_id)
558
.fetch_optional(&state.db)
559
.await;
560
561
let repo_commit = match repo_result {
562
+
Ok(Some(row)) => row.repo_root_cid,
563
_ => String::new(),
564
};
565
566
+
let record_count: i64 = sqlx::query_scalar!("SELECT COUNT(*) FROM records WHERE repo_id = $1", user_id)
567
.fetch_one(&state.db)
568
.await
569
+
.unwrap_or(Some(0))
570
.unwrap_or(0);
571
572
let blob_count: i64 =
573
+
sqlx::query_scalar!("SELECT COUNT(*) FROM blobs WHERE created_by_user = $1", user_id)
574
.fetch_one(&state.db)
575
.await
576
+
.unwrap_or(Some(0))
577
.unwrap_or(0);
578
579
let valid_did = did.starts_with("did:");
···
614
.unwrap_or("")
615
.replace("Bearer ", "");
616
617
+
let session = sqlx::query!(
618
r#"
619
SELECT s.did, k.key_bytes
620
FROM sessions s
···
622
JOIN user_keys k ON u.id = k.user_id
623
WHERE s.access_jwt = $1
624
"#,
625
+
token
626
)
627
.fetch_optional(&state.db)
628
.await;
629
630
let (did, key_bytes) = match session {
631
+
Ok(Some(row)) => (row.did, row.key_bytes),
632
Ok(None) => {
633
return (
634
StatusCode::UNAUTHORIZED,
···
654
.into_response();
655
}
656
657
+
let result = sqlx::query!("UPDATE users SET deactivated_at = NULL WHERE did = $1", did)
658
.execute(&state.db)
659
.await;
660
···
697
.unwrap_or("")
698
.replace("Bearer ", "");
699
700
+
let session = sqlx::query!(
701
r#"
702
SELECT s.did, k.key_bytes
703
FROM sessions s
···
705
JOIN user_keys k ON u.id = k.user_id
706
WHERE s.access_jwt = $1
707
"#,
708
+
token
709
)
710
.fetch_optional(&state.db)
711
.await;
712
713
let (did, key_bytes) = match session {
714
+
Ok(Some(row)) => (row.did, row.key_bytes),
715
Ok(None) => {
716
return (
717
StatusCode::UNAUTHORIZED,
···
737
.into_response();
738
}
739
740
+
let result = sqlx::query!("UPDATE users SET deactivated_at = NOW() WHERE did = $1", did)
741
.execute(&state.db)
742
.await;
743
···
786
.unwrap_or("")
787
.replace("Bearer ", "");
788
789
+
let session = sqlx::query!(
790
r#"
791
SELECT s.did, k.key_bytes, u.id as user_id
792
FROM sessions s
···
794
JOIN user_keys k ON u.id = k.user_id
795
WHERE s.access_jwt = $1
796
"#,
797
+
token
798
)
799
.fetch_optional(&state.db)
800
.await;
801
802
let (_did, key_bytes, user_id) = match session {
803
+
Ok(Some(row)) => (row.did, row.key_bytes, row.user_id),
804
Ok(None) => {
805
return (
806
StatusCode::UNAUTHORIZED,
···
826
.into_response();
827
}
828
829
+
let result = sqlx::query!("SELECT name, created_at, privileged FROM app_passwords WHERE user_id = $1 ORDER BY created_at DESC", user_id)
830
.fetch_all(&state.db)
831
.await;
832
···
835
let passwords: Vec<AppPassword> = rows
836
.iter()
837
.map(|row| {
838
AppPassword {
839
+
name: row.name.clone(),
840
+
created_at: row.created_at.to_rfc3339(),
841
+
privileged: row.privileged,
842
}
843
})
844
.collect();
···
891
.unwrap_or("")
892
.replace("Bearer ", "");
893
894
+
let session = sqlx::query!(
895
r#"
896
SELECT s.did, k.key_bytes, u.id as user_id
897
FROM sessions s
···
899
JOIN user_keys k ON u.id = k.user_id
900
WHERE s.access_jwt = $1
901
"#,
902
+
token
903
)
904
.fetch_optional(&state.db)
905
.await;
906
907
let (_did, key_bytes, user_id) = match session {
908
+
Ok(Some(row)) => (row.did, row.key_bytes, row.user_id),
909
Ok(None) => {
910
return (
911
StatusCode::UNAUTHORIZED,
···
940
.into_response();
941
}
942
943
+
let existing = sqlx::query!("SELECT id FROM app_passwords WHERE user_id = $1 AND name = $2", user_id, name)
944
.fetch_optional(&state.db)
945
.await;
946
···
977
let privileged = input.privileged.unwrap_or(false);
978
let created_at = chrono::Utc::now();
979
980
+
let result = sqlx::query!(
981
+
"INSERT INTO app_passwords (user_id, name, password_hash, created_at, privileged) VALUES ($1, $2, $3, $4, $5)",
982
+
user_id,
983
+
name,
984
+
password_hash,
985
+
created_at,
986
+
privileged
987
)
988
.execute(&state.db)
989
.await;
990
···
1035
.unwrap_or("")
1036
.replace("Bearer ", "");
1037
1038
+
let session = sqlx::query!(
1039
r#"
1040
SELECT s.did, k.key_bytes, u.id as user_id
1041
FROM sessions s
···
1043
JOIN user_keys k ON u.id = k.user_id
1044
WHERE s.access_jwt = $1
1045
"#,
1046
+
token
1047
)
1048
.fetch_optional(&state.db)
1049
.await;
1050
1051
let (_did, key_bytes, user_id) = match session {
1052
+
Ok(Some(row)) => (row.did, row.key_bytes, row.user_id),
1053
Ok(None) => {
1054
return (
1055
StatusCode::UNAUTHORIZED,
···
1084
.into_response();
1085
}
1086
1087
+
let result = sqlx::query!("DELETE FROM app_passwords WHERE user_id = $1 AND name = $2", user_id, name)
1088
.execute(&state.db)
1089
.await;
1090
+9
-15
src/repo/mod.rs
+9
-15
src/repo/mod.rs
···
5
use jacquard_repo::storage::BlockStore;
6
use multihash::Multihash;
7
use sha2::{Digest, Sha256};
8
-
use sqlx::{PgPool, Row};
9
10
#[derive(Clone)]
11
pub struct PostgresBlockStore {
···
21
impl BlockStore for PostgresBlockStore {
22
async fn get(&self, cid: &Cid) -> Result<Option<Bytes>, RepoError> {
23
let cid_bytes = cid.to_bytes();
24
-
let row = sqlx::query("SELECT data FROM blocks WHERE cid = $1")
25
-
.bind(cid_bytes)
26
.fetch_optional(&self.pool)
27
.await
28
.map_err(|e| RepoError::storage(e))?;
29
30
match row {
31
-
Some(row) => {
32
-
let data: Vec<u8> = row.get("data");
33
-
Ok(Some(Bytes::from(data)))
34
-
}
35
None => Ok(None),
36
}
37
}
···
44
let cid = Cid::new_v1(0x71, multihash);
45
let cid_bytes = cid.to_bytes();
46
47
-
sqlx::query("INSERT INTO blocks (cid, data) VALUES ($1, $2) ON CONFLICT (cid) DO NOTHING")
48
-
.bind(cid_bytes)
49
-
.bind(data)
50
.execute(&self.pool)
51
.await
52
.map_err(|e| RepoError::storage(e))?;
···
56
57
async fn has(&self, cid: &Cid) -> Result<bool, RepoError> {
58
let cid_bytes = cid.to_bytes();
59
-
let row = sqlx::query("SELECT 1 FROM blocks WHERE cid = $1")
60
-
.bind(cid_bytes)
61
.fetch_optional(&self.pool)
62
.await
63
.map_err(|e| RepoError::storage(e))?;
···
72
let blocks: Vec<_> = blocks.into_iter().collect();
73
for (cid, data) in blocks {
74
let cid_bytes = cid.to_bytes();
75
-
sqlx::query(
76
"INSERT INTO blocks (cid, data) VALUES ($1, $2) ON CONFLICT (cid) DO NOTHING",
77
)
78
-
.bind(cid_bytes)
79
-
.bind(data.as_ref())
80
.execute(&self.pool)
81
.await
82
.map_err(|e| RepoError::storage(e))?;
···
5
use jacquard_repo::storage::BlockStore;
6
use multihash::Multihash;
7
use sha2::{Digest, Sha256};
8
+
use sqlx::PgPool;
9
10
#[derive(Clone)]
11
pub struct PostgresBlockStore {
···
21
impl BlockStore for PostgresBlockStore {
22
async fn get(&self, cid: &Cid) -> Result<Option<Bytes>, RepoError> {
23
let cid_bytes = cid.to_bytes();
24
+
let row = sqlx::query!("SELECT data FROM blocks WHERE cid = $1", &cid_bytes)
25
.fetch_optional(&self.pool)
26
.await
27
.map_err(|e| RepoError::storage(e))?;
28
29
match row {
30
+
Some(row) => Ok(Some(Bytes::from(row.data))),
31
None => Ok(None),
32
}
33
}
···
40
let cid = Cid::new_v1(0x71, multihash);
41
let cid_bytes = cid.to_bytes();
42
43
+
sqlx::query!("INSERT INTO blocks (cid, data) VALUES ($1, $2) ON CONFLICT (cid) DO NOTHING", &cid_bytes, data)
44
.execute(&self.pool)
45
.await
46
.map_err(|e| RepoError::storage(e))?;
···
50
51
async fn has(&self, cid: &Cid) -> Result<bool, RepoError> {
52
let cid_bytes = cid.to_bytes();
53
+
let row = sqlx::query!("SELECT 1 as one FROM blocks WHERE cid = $1", &cid_bytes)
54
.fetch_optional(&self.pool)
55
.await
56
.map_err(|e| RepoError::storage(e))?;
···
65
let blocks: Vec<_> = blocks.into_iter().collect();
66
for (cid, data) in blocks {
67
let cid_bytes = cid.to_bytes();
68
+
let data_ref = data.as_ref();
69
+
sqlx::query!(
70
"INSERT INTO blocks (cid, data) VALUES ($1, $2) ON CONFLICT (cid) DO NOTHING",
71
+
&cid_bytes,
72
+
data_ref
73
)
74
.execute(&self.pool)
75
.await
76
.map_err(|e| RepoError::storage(e))?;
+39
-45
src/sync/mod.rs
+39
-45
src/sync/mod.rs
···
9
};
10
use serde::{Deserialize, Serialize};
11
use serde_json::json;
12
-
use sqlx::Row;
13
use tracing::{error, info};
14
15
#[derive(Deserialize)]
···
37
.into_response();
38
}
39
40
-
let result = sqlx::query(
41
r#"
42
SELECT r.repo_root_cid
43
FROM repos r
44
JOIN users u ON r.user_id = u.id
45
WHERE u.did = $1
46
"#,
47
)
48
-
.bind(did)
49
.fetch_optional(&state.db)
50
.await;
51
52
match result {
53
Ok(Some(row)) => {
54
-
let cid: String = row.get("repo_root_cid");
55
(
56
StatusCode::OK,
57
Json(GetLatestCommitOutput {
58
-
cid,
59
rev: chrono::Utc::now().timestamp_millis().to_string(),
60
}),
61
)
···
105
let limit = params.limit.unwrap_or(50).min(1000);
106
let cursor_did = params.cursor.as_deref().unwrap_or("");
107
108
-
let result = sqlx::query(
109
r#"
110
SELECT u.did, r.repo_root_cid
111
FROM repos r
···
114
ORDER BY u.did ASC
115
LIMIT $2
116
"#,
117
)
118
-
.bind(cursor_did)
119
-
.bind(limit + 1)
120
.fetch_all(&state.db)
121
.await;
122
···
127
.iter()
128
.take(limit as usize)
129
.map(|row| {
130
-
let did: String = row.get("did");
131
-
let head: String = row.get("repo_root_cid");
132
RepoInfo {
133
-
did,
134
-
head,
135
rev: chrono::Utc::now().timestamp_millis().to_string(),
136
active: true,
137
}
···
193
.into_response();
194
}
195
196
-
let user_exists = sqlx::query("SELECT id FROM users WHERE did = $1")
197
-
.bind(did)
198
.fetch_optional(&state.db)
199
.await;
200
···
217
Ok(Some(_)) => {}
218
}
219
220
-
let blob_result = sqlx::query("SELECT storage_key, mime_type FROM blobs WHERE cid = $1")
221
-
.bind(cid)
222
.fetch_optional(&state.db)
223
.await;
224
225
match blob_result {
226
Ok(Some(row)) => {
227
-
let storage_key: String = row.get("storage_key");
228
-
let mime_type: String = row.get("mime_type");
229
230
match state.blob_store.get(&storage_key).await {
231
Ok(data) => Response::builder()
···
290
let limit = params.limit.unwrap_or(500).min(1000);
291
let cursor_cid = params.cursor.as_deref().unwrap_or("");
292
293
-
let user_result = sqlx::query("SELECT id FROM users WHERE did = $1")
294
-
.bind(did)
295
.fetch_optional(&state.db)
296
.await;
297
298
-
let user_id: uuid::Uuid = match user_result {
299
-
Ok(Some(row)) => row.get("id"),
300
Ok(None) => {
301
return (
302
StatusCode::NOT_FOUND,
···
314
}
315
};
316
317
-
let result = if let Some(since) = ¶ms.since {
318
-
sqlx::query(
319
r#"
320
SELECT cid FROM blobs
321
WHERE created_by_user = $1 AND cid > $2 AND created_at > $3
322
ORDER BY cid ASC
323
LIMIT $4
324
"#,
325
)
326
-
.bind(user_id)
327
-
.bind(cursor_cid)
328
-
.bind(since)
329
-
.bind(limit + 1)
330
.fetch_all(&state.db)
331
.await
332
} else {
333
-
sqlx::query(
334
r#"
335
SELECT cid FROM blobs
336
WHERE created_by_user = $1 AND cid > $2
337
ORDER BY cid ASC
338
LIMIT $3
339
"#,
340
)
341
-
.bind(user_id)
342
-
.bind(cursor_cid)
343
-
.bind(limit + 1)
344
.fetch_all(&state.db)
345
.await
346
};
347
348
-
match result {
349
-
Ok(rows) => {
350
-
let has_more = rows.len() as i64 > limit;
351
-
let cids: Vec<String> = rows
352
-
.iter()
353
.take(limit as usize)
354
-
.map(|row| row.get("cid"))
355
.collect();
356
357
let next_cursor = if has_more {
···
406
.into_response();
407
}
408
409
-
let result = sqlx::query(
410
r#"
411
SELECT u.did, r.repo_root_cid
412
FROM users u
413
LEFT JOIN repos r ON u.id = r.user_id
414
WHERE u.did = $1
415
"#,
416
)
417
-
.bind(did)
418
.fetch_optional(&state.db)
419
.await;
420
421
match result {
422
Ok(Some(row)) => {
423
-
let user_did: String = row.get("did");
424
-
let repo_root: Option<String> = row.get("repo_root_cid");
425
-
426
-
let rev = repo_root.map(|_| chrono::Utc::now().timestamp_millis().to_string());
427
428
(
429
StatusCode::OK,
430
Json(GetRepoStatusOutput {
431
-
did: user_did,
432
active: true,
433
rev,
434
}),
···
9
};
10
use serde::{Deserialize, Serialize};
11
use serde_json::json;
12
use tracing::{error, info};
13
14
#[derive(Deserialize)]
···
36
.into_response();
37
}
38
39
+
let result = sqlx::query!(
40
r#"
41
SELECT r.repo_root_cid
42
FROM repos r
43
JOIN users u ON r.user_id = u.id
44
WHERE u.did = $1
45
"#,
46
+
did
47
)
48
.fetch_optional(&state.db)
49
.await;
50
51
match result {
52
Ok(Some(row)) => {
53
(
54
StatusCode::OK,
55
Json(GetLatestCommitOutput {
56
+
cid: row.repo_root_cid,
57
rev: chrono::Utc::now().timestamp_millis().to_string(),
58
}),
59
)
···
103
let limit = params.limit.unwrap_or(50).min(1000);
104
let cursor_did = params.cursor.as_deref().unwrap_or("");
105
106
+
let result = sqlx::query!(
107
r#"
108
SELECT u.did, r.repo_root_cid
109
FROM repos r
···
112
ORDER BY u.did ASC
113
LIMIT $2
114
"#,
115
+
cursor_did,
116
+
limit + 1
117
)
118
.fetch_all(&state.db)
119
.await;
120
···
125
.iter()
126
.take(limit as usize)
127
.map(|row| {
128
RepoInfo {
129
+
did: row.did.clone(),
130
+
head: row.repo_root_cid.clone(),
131
rev: chrono::Utc::now().timestamp_millis().to_string(),
132
active: true,
133
}
···
189
.into_response();
190
}
191
192
+
let user_exists = sqlx::query!("SELECT id FROM users WHERE did = $1", did)
193
.fetch_optional(&state.db)
194
.await;
195
···
212
Ok(Some(_)) => {}
213
}
214
215
+
let blob_result = sqlx::query!("SELECT storage_key, mime_type FROM blobs WHERE cid = $1", cid)
216
.fetch_optional(&state.db)
217
.await;
218
219
match blob_result {
220
Ok(Some(row)) => {
221
+
let storage_key = &row.storage_key;
222
+
let mime_type = &row.mime_type;
223
224
match state.blob_store.get(&storage_key).await {
225
Ok(data) => Response::builder()
···
284
let limit = params.limit.unwrap_or(500).min(1000);
285
let cursor_cid = params.cursor.as_deref().unwrap_or("");
286
287
+
let user_result = sqlx::query!("SELECT id FROM users WHERE did = $1", did)
288
.fetch_optional(&state.db)
289
.await;
290
291
+
let user_id = match user_result {
292
+
Ok(Some(row)) => row.id,
293
Ok(None) => {
294
return (
295
StatusCode::NOT_FOUND,
···
307
}
308
};
309
310
+
let cids_result: Result<Vec<String>, sqlx::Error> = if let Some(since) = ¶ms.since {
311
+
let since_time = chrono::DateTime::parse_from_rfc3339(since)
312
+
.map(|dt| dt.with_timezone(&chrono::Utc))
313
+
.unwrap_or_else(|_| chrono::Utc::now());
314
+
sqlx::query!(
315
r#"
316
SELECT cid FROM blobs
317
WHERE created_by_user = $1 AND cid > $2 AND created_at > $3
318
ORDER BY cid ASC
319
LIMIT $4
320
"#,
321
+
user_id,
322
+
cursor_cid,
323
+
since_time,
324
+
limit + 1
325
)
326
.fetch_all(&state.db)
327
.await
328
+
.map(|rows| rows.into_iter().map(|r| r.cid).collect())
329
} else {
330
+
sqlx::query!(
331
r#"
332
SELECT cid FROM blobs
333
WHERE created_by_user = $1 AND cid > $2
334
ORDER BY cid ASC
335
LIMIT $3
336
"#,
337
+
user_id,
338
+
cursor_cid,
339
+
limit + 1
340
)
341
.fetch_all(&state.db)
342
.await
343
+
.map(|rows| rows.into_iter().map(|r| r.cid).collect())
344
};
345
346
+
match cids_result {
347
+
Ok(cids) => {
348
+
let has_more = cids.len() as i64 > limit;
349
+
let cids: Vec<String> = cids
350
+
.into_iter()
351
.take(limit as usize)
352
.collect();
353
354
let next_cursor = if has_more {
···
403
.into_response();
404
}
405
406
+
let result = sqlx::query!(
407
r#"
408
SELECT u.did, r.repo_root_cid
409
FROM users u
410
LEFT JOIN repos r ON u.id = r.user_id
411
WHERE u.did = $1
412
"#,
413
+
did
414
)
415
.fetch_optional(&state.db)
416
.await;
417
418
match result {
419
Ok(Some(row)) => {
420
+
let rev = Some(chrono::Utc::now().timestamp_millis().to_string());
421
422
(
423
StatusCode::OK,
424
Json(GetRepoStatusOutput {
425
+
did: row.did,
426
active: true,
427
rev,
428
}),