-
Notifications
You must be signed in to change notification settings - Fork 0
/
custom-mysql.ts
56 lines (49 loc) · 1.89 KB
/
custom-mysql.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
import { NewShadowDatasetIterator, privatize } from "../src";
// A mock SQL query function, replace this with your own
let sqlQuery: (query: string) => Promise<number> =
(query) => Promise.resolve(Math.random());
function sqlAvg(whereFilter: string): Promise<number> {
return sqlQuery(`SELECT AVG(age) FROM Users ${whereFilter}`)
}
// Bare down for the hard part!
// Runs a query over every shadow "subset" of the SQL database where
// each subset removes 1 unique Identity. This simple iterator assumes the
// Users SQL table does not change over time.
function newSqlLikeShadowIterator(): NewShadowDatasetIterator<string> {
const pendingUserCount = sqlQuery("SELECT COUNT(*) FROM Users")
let i = 0
return async () => {
const userCount = await pendingUserCount
return {
// Exclude a different user for every subset
next: () => {
const isDone = i >= userCount
i++
return {
done: isDone,
// Remove user i to form the subset
value: isDone ?
undefined :
`WHERE id != ${i}`
}
}
}
}
}
async function customDatasetExample() {
const privatizedAvg = privatize(sqlAvg, {
maxEpsilon: 1,
maxCallCount: 100,
// Let's not stress out the database too much,
// max of 4 concurrent queries per privatizedAvg call
maxConcurrentCalls: 4,
newShadowIterator: newSqlLikeShadowIterator(),
})
// Run empty where clause to get the overall average age for all users,
// and add enough noise to ensure epsilon-differential privacy
const noisedResult = await privatizedAvg("")
// The final, privatized averge age as a number
const noisedAvgAge = noisedResult.result
console.log(noisedAvgAge)
}
customDatasetExample()