@mailwoman/tiger 8.0.0 → 8.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/constants.ts +12 -12
- package/county.ts +5 -2
- package/files.ts +4 -1
- package/geoid.ts +11 -9
- package/out/constants.d.ts +5 -5
- package/out/constants.d.ts.map +1 -1
- package/out/constants.js +0 -5
- package/out/constants.js.map +1 -1
- package/out/county.d.ts +5 -2
- package/out/county.d.ts.map +1 -1
- package/out/county.js +3 -2
- package/out/county.js.map +1 -1
- package/out/files.d.ts +1 -1
- package/out/files.d.ts.map +1 -1
- package/out/files.js +0 -1
- package/out/files.js.map +1 -1
- package/out/geoid.d.ts +14 -16
- package/out/geoid.d.ts.map +1 -1
- package/out/geoid.js +1 -2
- package/out/geoid.js.map +1 -1
- package/out/sdk/fetch.d.ts +18 -6
- package/out/sdk/fetch.d.ts.map +1 -1
- package/out/sdk/fetch.js +11 -5
- package/out/sdk/fetch.js.map +1 -1
- package/out/sdk/redistricting.d.ts +18 -6
- package/out/sdk/redistricting.d.ts.map +1 -1
- package/out/sdk/redistricting.js +12 -6
- package/out/sdk/redistricting.js.map +1 -1
- package/out/sdk/schema.d.ts +14 -7
- package/out/sdk/schema.d.ts.map +1 -1
- package/out/sdk/schema.js +4 -0
- package/out/sdk/schema.js.map +1 -1
- package/out/sdk/state/TIGERTractEntity.d.ts +1 -1
- package/out/sdk/state/TIGERTractEntity.d.ts.map +1 -1
- package/out/sdk/state/TIGERTractEntity.js +1 -1
- package/out/sdk/state/TIGERTractEntity.js.map +1 -1
- package/out/sdk/state/block-operations.d.ts +1 -1
- package/out/sdk/state/block-operations.d.ts.map +1 -1
- package/out/sdk/state/block-operations.js +0 -1
- package/out/sdk/state/block-operations.js.map +1 -1
- package/out/state.d.ts +343 -113
- package/out/state.d.ts.map +1 -1
- package/out/state.js +174 -57
- package/out/state.js.map +1 -1
- package/out/tabulation-block.d.ts +3 -3
- package/out/tabulation-block.d.ts.map +1 -1
- package/out/tabulation-block.js +1 -3
- package/out/tabulation-block.js.map +1 -1
- package/out/tools/race-dots-map.d.ts +30 -10
- package/out/tools/race-dots-map.d.ts.map +1 -1
- package/out/tools/race-dots-map.js +6 -2
- package/out/tools/race-dots-map.js.map +1 -1
- package/out/tools/race-dots.d.ts +24 -8
- package/out/tools/race-dots.d.ts.map +1 -1
- package/out/tools/race-dots.js +15 -5
- package/out/tools/race-dots.js.map +1 -1
- package/out/tools/serve-range.d.ts +12 -4
- package/out/tools/serve-range.d.ts.map +1 -1
- package/out/tools/serve-range.js.map +1 -1
- package/out/tract.d.ts +2 -2
- package/out/tract.d.ts.map +1 -1
- package/out/tract.js +1 -2
- package/out/tract.js.map +1 -1
- package/out/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -3
- package/sdk/fetch.ts +36 -11
- package/sdk/redistricting.ts +39 -12
- package/sdk/schema.ts +21 -7
- package/sdk/state/TIGERTractEntity.ts +1 -1
- package/sdk/state/block-operations.ts +7 -6
- package/state.ts +175 -57
- package/tabulation-block.ts +3 -3
- package/tools/race-dots-map.ts +35 -11
- package/tools/race-dots.ts +52 -12
- package/tools/serve-range.ts +16 -4
- package/tract.ts +2 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mailwoman/tiger",
|
|
3
|
-
"version": "8.
|
|
3
|
+
"version": "8.2.0",
|
|
4
4
|
"description": "US Census TIGER/Line data processing and analysis.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"census",
|
|
@@ -73,8 +73,8 @@
|
|
|
73
73
|
"test": "node ./out/sdk/TIGERService.test.js"
|
|
74
74
|
},
|
|
75
75
|
"dependencies": {
|
|
76
|
-
"@mailwoman/core": "8.
|
|
77
|
-
"@mailwoman/spatial": "8.
|
|
76
|
+
"@mailwoman/core": "8.2.0",
|
|
77
|
+
"@mailwoman/spatial": "8.2.0",
|
|
78
78
|
"@turf/boolean-contains": "^7.3.5",
|
|
79
79
|
"kysely": "^0.29.4",
|
|
80
80
|
"shapefile-parser": "^1.0.3",
|
package/sdk/fetch.ts
CHANGED
|
@@ -52,6 +52,7 @@ const LEVEL_DIR: Record<TIGERFetchLevel, string> = {
|
|
|
52
52
|
place: "PLACE",
|
|
53
53
|
addrfeat: "ADDRFEAT",
|
|
54
54
|
}
|
|
55
|
+
|
|
55
56
|
const LEVEL_TABLE: Record<TIGERFetchLevel, keyof TIGERDatabase> = {
|
|
56
57
|
tabblock20: "tabblock20",
|
|
57
58
|
place: "tiger_places",
|
|
@@ -59,21 +60,33 @@ const LEVEL_TABLE: Record<TIGERFetchLevel, keyof TIGERDatabase> = {
|
|
|
59
60
|
}
|
|
60
61
|
|
|
61
62
|
export interface FetchTIGEROptions {
|
|
62
|
-
/**
|
|
63
|
+
/**
|
|
64
|
+
* Two-digit state FIPS, e.g. `"06"`.
|
|
65
|
+
*/
|
|
63
66
|
stateFIPS: string
|
|
64
|
-
/**
|
|
67
|
+
/**
|
|
68
|
+
* TIGER level. Default `tabblock20`.
|
|
69
|
+
*/
|
|
65
70
|
level?: TIGERFetchLevel
|
|
66
|
-
/**
|
|
71
|
+
/**
|
|
72
|
+
* Vintage. Default 2020 for blocks (matches the 2020 P.L.), 2024 for place/addrfeat (current).
|
|
73
|
+
*/
|
|
67
74
|
vintage?: number
|
|
68
75
|
/**
|
|
69
76
|
* Output SQLite path. Default `<dataRoot>/tiger/tiger.db` (the name the corpus `tiger` adapter reads).
|
|
70
77
|
*/
|
|
71
78
|
outPath?: string
|
|
72
|
-
/**
|
|
79
|
+
/**
|
|
80
|
+
* Download cache + default output root.
|
|
81
|
+
*/
|
|
73
82
|
dataRoot?: string
|
|
74
|
-
/**
|
|
83
|
+
/**
|
|
84
|
+
* Optional three-digit county FIPS filter (blocks only — addrfeat is already per-county).
|
|
85
|
+
*/
|
|
75
86
|
county?: string
|
|
76
|
-
/**
|
|
87
|
+
/**
|
|
88
|
+
* Rows per insert. Default 1000.
|
|
89
|
+
*/
|
|
77
90
|
batchSize?: number
|
|
78
91
|
}
|
|
79
92
|
|
|
@@ -88,7 +101,9 @@ export interface FetchTIGERResult {
|
|
|
88
101
|
inserted: number
|
|
89
102
|
}
|
|
90
103
|
|
|
91
|
-
/**
|
|
104
|
+
/**
|
|
105
|
+
* The isp-nexus column map for `tabblock20`. Geometry rides along implicitly.
|
|
106
|
+
*/
|
|
92
107
|
function blockSelectSQL(layer: string, county?: string): string {
|
|
93
108
|
const where = county ? ` WHERE COUNTYFP20 = '${county}'` : ""
|
|
94
109
|
|
|
@@ -162,6 +177,7 @@ function runCapture(cmd: string, args: string[]): Promise<string> {
|
|
|
162
177
|
child.stdout.on("data", (d) => (out += d))
|
|
163
178
|
child.stderr.on("data", (d) => (err += d))
|
|
164
179
|
child.on("error", reject)
|
|
180
|
+
|
|
165
181
|
child.on("close", (code) =>
|
|
166
182
|
code === 0 ? resolve(out) : reject(new Error(`${cmd} exited ${code}: ${err.slice(0, 500)}`))
|
|
167
183
|
)
|
|
@@ -178,6 +194,7 @@ async function downloadIfNeeded(url: string, dest: string): Promise<boolean> {
|
|
|
178
194
|
// corrupt cache — re-download
|
|
179
195
|
}
|
|
180
196
|
}
|
|
197
|
+
|
|
181
198
|
const tmp = dest + ".tmp"
|
|
182
199
|
const res = await fetch(url, { redirect: "follow" })
|
|
183
200
|
|
|
@@ -188,7 +205,9 @@ async function downloadIfNeeded(url: string, dest: string): Promise<boolean> {
|
|
|
188
205
|
return false
|
|
189
206
|
}
|
|
190
207
|
|
|
191
|
-
/**
|
|
208
|
+
/**
|
|
209
|
+
* Scrape the ADDRFEAT directory listing for a state's county FIPS codes.
|
|
210
|
+
*/
|
|
192
211
|
async function discoverCounties(state: string, vintage: number): Promise<string[]> {
|
|
193
212
|
const res = await fetch(`${CENSUS_HOST}/geo/tiger/TIGER${vintage}/ADDRFEAT/`, { redirect: "follow" })
|
|
194
213
|
|
|
@@ -201,7 +220,7 @@ async function discoverCounties(state: string, vintage: number): Promise<string[
|
|
|
201
220
|
counties.add(m[1]!)
|
|
202
221
|
}
|
|
203
222
|
|
|
204
|
-
return [...counties].
|
|
223
|
+
return [...counties].toSorted()
|
|
205
224
|
}
|
|
206
225
|
|
|
207
226
|
/**
|
|
@@ -227,7 +246,7 @@ export async function* fetchTIGER(options: FetchTIGEROptions): AsyncGenerator<Fe
|
|
|
227
246
|
// Source units: one (per-state) for block/place; one per county for addrfeat.
|
|
228
247
|
const geoCodes = level === "addrfeat" ? await discoverCounties(state, vintage) : [""]
|
|
229
248
|
|
|
230
|
-
if (level === "addrfeat" && geoCodes.length
|
|
249
|
+
if (level === "addrfeat" && !geoCodes.length) {
|
|
231
250
|
throw new Error(`No ADDRFEAT counties found for state ${state} vintage ${vintage}`)
|
|
232
251
|
}
|
|
233
252
|
|
|
@@ -267,6 +286,7 @@ export async function* fetchTIGER(options: FetchTIGEROptions): AsyncGenerator<Fe
|
|
|
267
286
|
|
|
268
287
|
let inserted = 0
|
|
269
288
|
let batch: Row[] = []
|
|
289
|
+
|
|
270
290
|
const flush = async () => {
|
|
271
291
|
if (!batch.length) return
|
|
272
292
|
const rows = batch
|
|
@@ -303,9 +323,13 @@ export async function* fetchTIGER(options: FetchTIGEROptions): AsyncGenerator<Fe
|
|
|
303
323
|
],
|
|
304
324
|
{ stdio: ["ignore", "pipe", "pipe"] }
|
|
305
325
|
)
|
|
326
|
+
|
|
306
327
|
let stderr = ""
|
|
307
328
|
child.stderr.on("data", (d) => (stderr += d))
|
|
308
|
-
|
|
329
|
+
|
|
330
|
+
const exited = new Promise<number>((resolve) => {
|
|
331
|
+
child.on("close", (code) => resolve(code ?? 0))
|
|
332
|
+
})
|
|
309
333
|
|
|
310
334
|
// GeoJSONSeq is line-delimited; keep the per-line `JSON.parse` in a try/catch so a malformed
|
|
311
335
|
// record is tolerated (skipped), not thrown.
|
|
@@ -329,6 +353,7 @@ export async function* fetchTIGER(options: FetchTIGEROptions): AsyncGenerator<Fe
|
|
|
329
353
|
yield { phase: "load", inserted, total: 0 }
|
|
330
354
|
}
|
|
331
355
|
}
|
|
356
|
+
|
|
332
357
|
await flush()
|
|
333
358
|
|
|
334
359
|
const code = await exited
|
package/sdk/redistricting.ts
CHANGED
|
@@ -33,18 +33,26 @@ import { initializeTIGERSchema, TIGER_PRAGMAS, type PLBlockTable, type TIGERData
|
|
|
33
33
|
|
|
34
34
|
const REDISTRICTING_BASE =
|
|
35
35
|
"https://www2.census.gov/programs-surveys/decennial/2020/data/01-Redistricting_File--PL_94-171"
|
|
36
|
+
|
|
36
37
|
const DEFAULT_DATA_ROOT = mailwomanDataRoot()
|
|
37
38
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
39
|
+
/**
|
|
40
|
+
* P.L. 94-171 (2020) pipe-delimited field offsets (0-based). Geographic header:
|
|
41
|
+
* …|SUMLEV(2)|…|LOGRECNO(7)|GEOID(8)|GEOCODE(9)|… — GEOCODE is the bare 15-char block FIPS (matches TIGER GEOID20);
|
|
42
|
+
* SUMLEV 750 = tabulation block.
|
|
43
|
+
*/
|
|
41
44
|
const GEO_SUMLEV = 2
|
|
42
45
|
const GEO_LOGRECNO = 7
|
|
43
46
|
const GEO_GEOCODE = 9
|
|
44
|
-
|
|
47
|
+
/**
|
|
48
|
+
* Segment 1: FILEID|STUSAB|CHARITER|CIFSN|LOGRECNO(4)| P1×71 | P2×73. P0020001 is at index 76.
|
|
49
|
+
*/
|
|
45
50
|
const SEG_LOGRECNO = 4
|
|
46
51
|
const P2 = (fieldNo: number) => 76 + (fieldNo - 1)
|
|
47
|
-
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* The eight P2 categories that partition the total (P0020001), in `pl_block` column order.
|
|
55
|
+
*/
|
|
48
56
|
const CATEGORY_INDEX = {
|
|
49
57
|
pop_total: P2(1),
|
|
50
58
|
hispanic: P2(2), // Hispanic or Latino (any race)
|
|
@@ -58,17 +66,29 @@ const CATEGORY_INDEX = {
|
|
|
58
66
|
} as const
|
|
59
67
|
|
|
60
68
|
export interface FetchRedistrictingOptions {
|
|
61
|
-
/**
|
|
69
|
+
/**
|
|
70
|
+
* Two-digit state FIPS, e.g. `"06"`.
|
|
71
|
+
*/
|
|
62
72
|
stateFIPS: string
|
|
63
|
-
/**
|
|
73
|
+
/**
|
|
74
|
+
* Decennial vintage. Default 2020 (the only P.L. 94-171 release this parses).
|
|
75
|
+
*/
|
|
64
76
|
vintage?: number
|
|
65
|
-
/**
|
|
77
|
+
/**
|
|
78
|
+
* Output SQLite path. Default `<dataRoot>/tiger/tiger.db` (same DB as `fetchTIGER`).
|
|
79
|
+
*/
|
|
66
80
|
outPath?: string
|
|
67
|
-
/**
|
|
81
|
+
/**
|
|
82
|
+
* Download cache + default output root.
|
|
83
|
+
*/
|
|
68
84
|
dataRoot?: string
|
|
69
|
-
/**
|
|
85
|
+
/**
|
|
86
|
+
* Optional three-digit county FIPS filter, e.g. `"059"`.
|
|
87
|
+
*/
|
|
70
88
|
county?: string
|
|
71
|
-
/**
|
|
89
|
+
/**
|
|
90
|
+
* Rows per insert. Default 2000.
|
|
91
|
+
*/
|
|
72
92
|
batchSize?: number
|
|
73
93
|
}
|
|
74
94
|
|
|
@@ -92,6 +112,7 @@ function runCapture(cmd: string, args: string[]): Promise<string> {
|
|
|
92
112
|
child.stdout.on("data", (d) => (out += d))
|
|
93
113
|
child.stderr.on("data", (d) => (err += d))
|
|
94
114
|
child.on("error", reject)
|
|
115
|
+
|
|
95
116
|
child.on("close", (code) =>
|
|
96
117
|
code === 0 ? resolve(out) : reject(new Error(`${cmd} exited ${code}: ${err.slice(0, 500)}`))
|
|
97
118
|
)
|
|
@@ -108,6 +129,7 @@ async function downloadIfNeeded(url: string, dest: string): Promise<boolean> {
|
|
|
108
129
|
// corrupt cache — re-download
|
|
109
130
|
}
|
|
110
131
|
}
|
|
132
|
+
|
|
111
133
|
const tmp = dest + ".tmp"
|
|
112
134
|
const res = await fetch(url, { redirect: "follow" })
|
|
113
135
|
|
|
@@ -145,7 +167,7 @@ export async function* fetchRedistricting(
|
|
|
145
167
|
|
|
146
168
|
if (!abbr) throw new Error(`Unknown state FIPS "${state}"`)
|
|
147
169
|
const stateName = StateName[abbr as keyof typeof StateName]
|
|
148
|
-
const dirName = stateName.
|
|
170
|
+
const dirName = stateName.replaceAll(" ", "_")
|
|
149
171
|
const fileAbbr = abbr.toLowerCase()
|
|
150
172
|
|
|
151
173
|
const cacheDir = join(dataRoot, "census", "redistricting", String(vintage), state)
|
|
@@ -169,6 +191,7 @@ export async function* fetchRedistricting(
|
|
|
169
191
|
// Pass 1: header → LOGRECNO → GEOID for the blocks we want.
|
|
170
192
|
const prefix = options.county ? state + options.county : state
|
|
171
193
|
const logToGeoid = new Map<string, string>()
|
|
194
|
+
|
|
172
195
|
await eachLine(geoPath, (line) => {
|
|
173
196
|
const f = line.split("|")
|
|
174
197
|
|
|
@@ -178,6 +201,7 @@ export async function* fetchRedistricting(
|
|
|
178
201
|
if (!geoid.startsWith(prefix)) return
|
|
179
202
|
logToGeoid.set(f[GEO_LOGRECNO] ?? "", geoid)
|
|
180
203
|
})
|
|
204
|
+
|
|
181
205
|
const total = logToGeoid.size
|
|
182
206
|
yield { phase: "header", blocks: total }
|
|
183
207
|
|
|
@@ -195,6 +219,7 @@ export async function* fetchRedistricting(
|
|
|
195
219
|
|
|
196
220
|
let inserted = 0
|
|
197
221
|
let batch: PLBlockTable[] = []
|
|
222
|
+
|
|
198
223
|
const flush = async () => {
|
|
199
224
|
if (!batch.length) return
|
|
200
225
|
const rows = batch
|
|
@@ -210,6 +235,7 @@ export async function* fetchRedistricting(
|
|
|
210
235
|
const geoid = logToGeoid.get(f[SEG_LOGRECNO] ?? "")
|
|
211
236
|
|
|
212
237
|
if (!geoid) continue
|
|
238
|
+
|
|
213
239
|
batch.push({
|
|
214
240
|
GEOID: geoid,
|
|
215
241
|
pop_total: Number(f[CATEGORY_INDEX.pop_total] ?? 0),
|
|
@@ -228,6 +254,7 @@ export async function* fetchRedistricting(
|
|
|
228
254
|
yield { phase: "load", inserted, total }
|
|
229
255
|
}
|
|
230
256
|
}
|
|
257
|
+
|
|
231
258
|
await flush()
|
|
232
259
|
|
|
233
260
|
yield { phase: "load", inserted, total }
|
package/sdk/schema.ts
CHANGED
|
@@ -10,9 +10,10 @@
|
|
|
10
10
|
* back with `JSON.parse`).
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
import { sql, type
|
|
13
|
+
import { sql, type Kysely } from "kysely"
|
|
14
|
+
|
|
15
|
+
export { type Generated } from "kysely"
|
|
14
16
|
|
|
15
|
-
/** Kysely row type for `tabblock20`. Geometry is a GeoJSON string. */
|
|
16
17
|
export interface TIGERBlockTable {
|
|
17
18
|
GEOID: string
|
|
18
19
|
state_code: string
|
|
@@ -47,7 +48,9 @@ export interface PLBlockTable {
|
|
|
47
48
|
multi: number
|
|
48
49
|
}
|
|
49
50
|
|
|
50
|
-
/**
|
|
51
|
+
/**
|
|
52
|
+
* Kysely row type for `tiger_streets` (ADDRFEAT — named street segments + ZIPs, per county).
|
|
53
|
+
*/
|
|
51
54
|
export interface TIGERStreetTable {
|
|
52
55
|
linearid: string
|
|
53
56
|
fullname: string
|
|
@@ -56,7 +59,9 @@ export interface TIGERStreetTable {
|
|
|
56
59
|
statefp: string
|
|
57
60
|
}
|
|
58
61
|
|
|
59
|
-
/**
|
|
62
|
+
/**
|
|
63
|
+
* Kysely row type for `tiger_places` (PLACE — incorporated/census places, per state).
|
|
64
|
+
*/
|
|
60
65
|
export interface TIGERPlaceTable {
|
|
61
66
|
geoid: string
|
|
62
67
|
name: string
|
|
@@ -66,7 +71,9 @@ export interface TIGERPlaceTable {
|
|
|
66
71
|
classfp: string | null
|
|
67
72
|
}
|
|
68
73
|
|
|
69
|
-
/**
|
|
74
|
+
/**
|
|
75
|
+
* The TIGER database schema, for `new DatabaseClient<TIGERDatabase>(...)`.
|
|
76
|
+
*/
|
|
70
77
|
export interface TIGERDatabase {
|
|
71
78
|
tabblock20: TIGERBlockTable
|
|
72
79
|
pl_block: PLBlockTable
|
|
@@ -74,8 +81,9 @@ export interface TIGERDatabase {
|
|
|
74
81
|
tiger_places: TIGERPlaceTable
|
|
75
82
|
}
|
|
76
83
|
|
|
77
|
-
/**
|
|
78
|
-
|
|
84
|
+
/**
|
|
85
|
+
* Marker so callers can opt into `Generated` columns later without importing kysely here.
|
|
86
|
+
*/
|
|
79
87
|
|
|
80
88
|
/**
|
|
81
89
|
* Build-tuning PRAGMAs, run raw before any table is created (`page_size`/`auto_vacuum` only take effect on an empty DB,
|
|
@@ -139,18 +147,21 @@ export async function initializeTIGERSchema(db: Kysely<TIGERDatabase>): Promise<
|
|
|
139
147
|
// No index on GEOID alone — it's the PRIMARY KEY, which already carries a unique index. The prior
|
|
140
148
|
// schema's idx_tabblock20_geoid duplicated that for nothing (double insert cost, double footprint).
|
|
141
149
|
await db.schema.createIndex("idx_tabblock20_state_code").ifNotExists().on("tabblock20").column("state_code").execute()
|
|
150
|
+
|
|
142
151
|
await db.schema
|
|
143
152
|
.createIndex("idx_tabblock20_state_county")
|
|
144
153
|
.ifNotExists()
|
|
145
154
|
.on("tabblock20")
|
|
146
155
|
.columns(["state_code", "county_code"])
|
|
147
156
|
.execute()
|
|
157
|
+
|
|
148
158
|
await db.schema
|
|
149
159
|
.createIndex("idx_tabblock20_state_county_tract")
|
|
150
160
|
.ifNotExists()
|
|
151
161
|
.on("tabblock20")
|
|
152
162
|
.columns(["state_code", "county_code", "tract_code"])
|
|
153
163
|
.execute()
|
|
164
|
+
|
|
154
165
|
await db.schema.createIndex("idx_tabblock20_population").ifNotExists().on("tabblock20").column("population").execute()
|
|
155
166
|
|
|
156
167
|
await db.schema
|
|
@@ -180,7 +191,9 @@ export async function initializeTIGERSchema(db: Kysely<TIGERDatabase>): Promise<
|
|
|
180
191
|
.addColumn("zipr", "text")
|
|
181
192
|
.addColumn("statefp", "text", (c) => c.notNull())
|
|
182
193
|
.execute()
|
|
194
|
+
|
|
183
195
|
await db.schema.createIndex("idx_tiger_streets_statefp").ifNotExists().on("tiger_streets").column("statefp").execute()
|
|
196
|
+
|
|
184
197
|
await db.schema
|
|
185
198
|
.createIndex("idx_tiger_streets_linearid")
|
|
186
199
|
.ifNotExists()
|
|
@@ -198,6 +211,7 @@ export async function initializeTIGERSchema(db: Kysely<TIGERDatabase>): Promise<
|
|
|
198
211
|
.addColumn("namelsad", "text")
|
|
199
212
|
.addColumn("classfp", "text")
|
|
200
213
|
.execute()
|
|
214
|
+
|
|
201
215
|
await db.schema.createIndex("idx_tiger_places_statefp").ifNotExists().on("tiger_places").column("statefp").execute()
|
|
202
216
|
await db.schema.createIndex("idx_tiger_places_geoid").ifNotExists().on("tiger_places").column("geoid").execute()
|
|
203
217
|
}
|
|
@@ -6,13 +6,13 @@
|
|
|
6
6
|
|
|
7
7
|
import type { GeometryLiteral, MultiPolygonLiteral } from "@mailwoman/spatial"
|
|
8
8
|
import { wellKnownGeometryToGeoJSON } from "@mailwoman/spatial/sdk"
|
|
9
|
-
import {
|
|
9
|
+
import type {
|
|
10
10
|
FIPSStateCode,
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
11
|
+
FIPSBlockGeoID,
|
|
12
|
+
FIPSTractCode,
|
|
13
|
+
TIGERBlockFeature,
|
|
14
|
+
TIGERBlockFeatureCollection,
|
|
15
|
+
TIGERTabulatedBlockProperties,
|
|
16
16
|
} from "@mailwoman/tiger"
|
|
17
17
|
|
|
18
18
|
export interface StateBlockIntersectionCriteria {
|
|
@@ -57,6 +57,7 @@ export function parseTIGERBlockFromRow({ serializedGeometry, ...properties }: TI
|
|
|
57
57
|
*/
|
|
58
58
|
export function parseTIGERBlockFeatureCollectionFromRows(rows: TIGERBlockRow[]): TIGERBlockFeatureCollection {
|
|
59
59
|
const features = rows.map(parseTIGERBlockFromRow)
|
|
60
|
+
|
|
60
61
|
const featureCollection: TIGERBlockFeatureCollection = {
|
|
61
62
|
type: "FeatureCollection",
|
|
62
63
|
features,
|