summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGalen Guyer <galen@galenguyer.com>2022-11-08 01:29:35 -0500
committerGalen Guyer <galen@galenguyer.com>2022-11-08 01:29:35 -0500
commit02f49120a3eabe2f855f219682a3fb0fd987db85 (patch)
treea2b3330ca69a288c9dfdef4ea8d0fa1709981aee
parent0dea469a59b14905a81dd97dc2e3d026d9f02250 (diff)
SQL code editor and table stuff
-rw-r--r--.gitignore1
-rw-r--r--package.json5
-rw-r--r--pnpm-lock.yaml181
-rw-r--r--src/App.css9
-rw-r--r--src/App.js68
-rw-r--r--src/Table.css23
-rw-r--r--src/Table.js38
-rw-r--r--src/schema.js168
8 files changed, 473 insertions, 20 deletions
diff --git a/.gitignore b/.gitignore
index 96db806..2a59b24 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,3 +2,4 @@ node_modules/
dist/
public/data/
+public/fcc.db
diff --git a/package.json b/package.json
index 9c4fe7f..904fc72 100644
--- a/package.json
+++ b/package.json
@@ -5,7 +5,7 @@
"main": "index.js",
"scripts": {
"start": "webpack-dev-server --mode development",
- "build": "webpack --mode production",
+ "build": "NODE_ENV=production webpack",
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
@@ -28,6 +28,9 @@
"webpack-dev-server": "^4.11.1"
},
"dependencies": {
+ "@codemirror/commands": "^6.1.2",
+ "@codemirror/lang-sql": "^6.3.2",
+ "@uiw/react-codemirror": "^4.12.4",
"lodash": "^4.17.21",
"react": "^18.2.0",
"react-dom": "^18.2.0",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index c13b802..5134c2e 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -5,7 +5,10 @@ specifiers:
'@babel/core': ^7.20.2
'@babel/preset-env': ^7.20.2
'@babel/preset-react': ^7.18.6
+ '@codemirror/commands': ^6.1.2
+ '@codemirror/lang-sql': ^6.3.2
'@pmmmwh/react-refresh-webpack-plugin': ^0.5.8
+ '@uiw/react-codemirror': ^4.12.4
babel-loader: ^9.1.0
copy-webpack-plugin: ^11.0.0
css-loader: ^6.7.1
@@ -21,6 +24,9 @@ specifiers:
webpack-dev-server: ^4.11.1
dependencies:
+ '@codemirror/commands': 6.1.2
+ '@codemirror/lang-sql': 6.3.2_4edla6ezzmbrt7zherv36dfe34
+ '@uiw/react-codemirror': 4.12.4_kla4oh6andn33cozt3edwlrbei
lodash: 4.17.21
react: 18.2.0
react-dom: 18.2.0_react@18.2.0
@@ -1241,7 +1247,6 @@ packages:
engines: {node: '>=6.9.0'}
dependencies:
regenerator-runtime: 0.13.10
- dev: true
/@babel/template/7.18.10:
resolution: {integrity: sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==}
@@ -1279,6 +1284,90 @@ packages:
to-fast-properties: 2.0.0
dev: true
+ /@codemirror/autocomplete/6.3.0_7ogqid446aq55x3kbijxdvvhgq:
+ resolution: {integrity: sha512-4jEvh3AjJZTDKazd10J6ZsCIqaYxDMCeua5ouQxY8hlFIml+nr7le0SgBhT3SIytFBmdzPK3AUhXGuW3T79nVg==}
+ peerDependencies:
+ '@codemirror/language': ^6.0.0
+ '@codemirror/state': ^6.0.0
+ '@codemirror/view': ^6.0.0
+ '@lezer/common': ^1.0.0
+ dependencies:
+ '@codemirror/language': 6.3.0
+ '@codemirror/state': 6.1.2
+ '@codemirror/view': 6.4.1
+ '@lezer/common': 1.0.1
+ dev: false
+
+ /@codemirror/commands/6.1.2:
+ resolution: {integrity: sha512-sO3jdX1s0pam6lIdeSJLMN3DQ6mPEbM4yLvyKkdqtmd/UDwhXA5+AwFJ89rRXm6vTeOXBsE5cAmlos/t7MJdgg==}
+ dependencies:
+ '@codemirror/language': 6.3.0
+ '@codemirror/state': 6.1.2
+ '@codemirror/view': 6.4.1
+ '@lezer/common': 1.0.1
+ dev: false
+
+ /@codemirror/lang-sql/6.3.2_4edla6ezzmbrt7zherv36dfe34:
+ resolution: {integrity: sha512-lbk2jBVvVK6NkIEn6HU3RwLh368qEcGP5bknwv6kiLGffFZHNoXj/J/F/YNXSynsgswapBofb3J6yVwsjXYQPw==}
+ dependencies:
+ '@codemirror/autocomplete': 6.3.0_7ogqid446aq55x3kbijxdvvhgq
+ '@codemirror/language': 6.3.0
+ '@codemirror/state': 6.1.2
+ '@lezer/highlight': 1.1.2
+ '@lezer/lr': 1.2.4
+ transitivePeerDependencies:
+ - '@codemirror/view'
+ - '@lezer/common'
+ dev: false
+
+ /@codemirror/language/6.3.0:
+ resolution: {integrity: sha512-6jOE5DEt6sKD46SXhn3xPbBehn+l48ACcA6Uxs2k+E2YNH9XGF5WdGMTYr2DlggfK4h0QZBK6zEb5S7lkTriWA==}
+ dependencies:
+ '@codemirror/state': 6.1.2
+ '@codemirror/view': 6.4.1
+ '@lezer/common': 1.0.1
+ '@lezer/highlight': 1.1.2
+ '@lezer/lr': 1.2.4
+ style-mod: 4.0.0
+ dev: false
+
+ /@codemirror/lint/6.0.0:
+ resolution: {integrity: sha512-nUUXcJW1Xp54kNs+a1ToPLK8MadO0rMTnJB8Zk4Z8gBdrN0kqV7uvUraU/T2yqg+grDNR38Vmy/MrhQN/RgwiA==}
+ dependencies:
+ '@codemirror/state': 6.1.2
+ '@codemirror/view': 6.4.1
+ crelt: 1.0.5
+ dev: false
+
+ /@codemirror/search/6.2.2:
+ resolution: {integrity: sha512-2pWY599zXk+lSoJ2iv9EuTO4gB7lhgBPLPwFb/zTbimFH4NmZSaKzJSV51okjABZ7/Rj0DYy5klWbIgaJh2LoQ==}
+ dependencies:
+ '@codemirror/state': 6.1.2
+ '@codemirror/view': 6.4.1
+ crelt: 1.0.5
+ dev: false
+
+ /@codemirror/state/6.1.2:
+ resolution: {integrity: sha512-Mxff85Hp5va+zuj+H748KbubXjrinX/k28lj43H14T2D0+4kuvEFIEIO7hCEcvBT8ubZyIelt9yGOjj2MWOEQA==}
+ dev: false
+
+ /@codemirror/theme-one-dark/6.1.0:
+ resolution: {integrity: sha512-AiTHtFRu8+vWT9wWUWDM+cog6ZwgivJogB1Tm/g40NIpLwph7AnmxrSzWfvJN5fBVufsuwBxecQCNmdcR5D7Aw==}
+ dependencies:
+ '@codemirror/language': 6.3.0
+ '@codemirror/state': 6.1.2
+ '@codemirror/view': 6.4.1
+ '@lezer/highlight': 1.1.2
+ dev: false
+
+ /@codemirror/view/6.4.1:
+ resolution: {integrity: sha512-QdBpD6E5HYx6YFXXhqwrRyQ83w7CxWZnchM4QpWBVkkmV7/oJT8N+yz2KAi2iRaLObc/aOf7C2RCQTO2yswF8A==}
+ dependencies:
+ '@codemirror/state': 6.1.2
+ style-mod: 4.0.0
+ w3c-keyname: 2.2.6
+ dev: false
+
/@discoveryjs/json-ext/0.5.7:
resolution: {integrity: sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==}
engines: {node: '>=10.0.0'}
@@ -1333,6 +1422,22 @@ packages:
resolution: {integrity: sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==}
dev: true
+ /@lezer/common/1.0.1:
+ resolution: {integrity: sha512-8TR5++Q/F//tpDsLd5zkrvEX5xxeemafEaek7mUp7Y+bI8cKQXdSqhzTOBaOogETcMOVr0pT3BBPXp13477ciw==}
+ dev: false
+
+ /@lezer/highlight/1.1.2:
+ resolution: {integrity: sha512-CAun1WR1glxG9ZdOokTZwXbcwB7PXkIEyZRUMFBVwSrhTcogWq634/ByNImrkUnQhjju6xsIaOBIxvcRJtplXQ==}
+ dependencies:
+ '@lezer/common': 1.0.1
+ dev: false
+
+ /@lezer/lr/1.2.4:
+ resolution: {integrity: sha512-L/52/oMJBFXXx8qBYF4UgktLP2geQ/qn5Fd8+5L/mqlLLCB9+qdKktFAtejd9FdFMaFx6lrP5rmLz4sN3Kplcg==}
+ dependencies:
+ '@lezer/common': 1.0.1
+ dev: false
+
/@nicolo-ribaudo/chokidar-2/2.1.8-no-fsevents.3:
resolution: {integrity: sha512-s88O1aVtXftvp5bCPB7WnmXc5IwOZZ7YPuwNPt+GtOOXpPvad1LfbmjYv+qII7zP6RU2QGnqve27dnLycEnyEQ==}
requiresBuild: true
@@ -1516,6 +1621,53 @@ packages:
'@types/node': 18.11.9
dev: true
+ /@uiw/codemirror-extensions-basic-setup/4.12.4_agsa3mk4x2udiledv2pz7napju:
+ resolution: {integrity: sha512-owSCcRBtS2wYjxgBFkuIjfjWJHsR8AxgsQtqPpHB/6U0zCLuzKS/OM5ZRS2T3rdOizg0hCPztVvmshWeKjF+qw==}
+ peerDependencies:
+ '@codemirror/autocomplete': '>=6.0.0'
+ '@codemirror/commands': '>=6.0.0'
+ '@codemirror/language': '>=6.0.0'
+ '@codemirror/lint': '>=6.0.0'
+ '@codemirror/search': '>=6.0.0'
+ '@codemirror/state': '>=6.0.0'
+ '@codemirror/view': '>=6.0.0'
+ dependencies:
+ '@codemirror/autocomplete': 6.3.0_7ogqid446aq55x3kbijxdvvhgq
+ '@codemirror/commands': 6.1.2
+ '@codemirror/language': 6.3.0
+ '@codemirror/lint': 6.0.0
+ '@codemirror/search': 6.2.2
+ '@codemirror/state': 6.1.2
+ '@codemirror/view': 6.4.1
+ dev: false
+
+ /@uiw/react-codemirror/4.12.4_kla4oh6andn33cozt3edwlrbei:
+ resolution: {integrity: sha512-92TAvN2z5snPjPtJDLmbqrqsXXYFYlBnWraXZuDc1XGaw80tB26ZkdEW79CD2QM4Y9LhFIt+sauwlmiAVDs/5A==}
+ peerDependencies:
+ '@babel/runtime': '>=7.11.0'
+ '@codemirror/state': '>=6.0.0'
+ '@codemirror/theme-one-dark': '>=6.0.0'
+ '@codemirror/view': '>=6.0.0'
+ codemirror: '>=6.0.0'
+ react: '>=16.8.0'
+ react-dom: '>=16.8.0'
+ dependencies:
+ '@babel/runtime': 7.20.1
+ '@codemirror/commands': 6.1.2
+ '@codemirror/state': 6.1.2
+ '@codemirror/theme-one-dark': 6.1.0
+ '@codemirror/view': 6.4.1
+ '@uiw/codemirror-extensions-basic-setup': 4.12.4_agsa3mk4x2udiledv2pz7napju
+ codemirror: 6.0.1_@lezer+common@1.0.1
+ react: 18.2.0
+ react-dom: 18.2.0_react@18.2.0
+ transitivePeerDependencies:
+ - '@codemirror/autocomplete'
+ - '@codemirror/language'
+ - '@codemirror/lint'
+ - '@codemirror/search'
+ dev: false
+
/@webassemblyjs/ast/1.11.1:
resolution: {integrity: sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==}
dependencies:
@@ -1943,6 +2095,20 @@ packages:
shallow-clone: 3.0.1
dev: true
+ /codemirror/6.0.1_@lezer+common@1.0.1:
+ resolution: {integrity: sha512-J8j+nZ+CdWmIeFIGXEFbFPtpiYacFMDR8GlHK3IyHQJMCaVRfGx9NT+Hxivv1ckLWPvNdZqndbr/7lVhrf/Svg==}
+ dependencies:
+ '@codemirror/autocomplete': 6.3.0_7ogqid446aq55x3kbijxdvvhgq
+ '@codemirror/commands': 6.1.2
+ '@codemirror/language': 6.3.0
+ '@codemirror/lint': 6.0.0
+ '@codemirror/search': 6.2.2
+ '@codemirror/state': 6.1.2
+ '@codemirror/view': 6.4.1
+ transitivePeerDependencies:
+ - '@lezer/common'
+ dev: false
+
/color-convert/1.9.3:
resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==}
dependencies:
@@ -2069,6 +2235,10 @@ packages:
resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==}
dev: true
+ /crelt/1.0.5:
+ resolution: {integrity: sha512-+BO9wPPi+DWTDcNYhr/W90myha8ptzftZT+LwcmUbbok0rcP/fequmFYCw8NMoH7pkAZQzU78b3kYrlua5a9eA==}
+ dev: false
+
/cross-spawn/7.0.3:
resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==}
engines: {node: '>= 8'}
@@ -3320,7 +3490,6 @@ packages:
/regenerator-runtime/0.13.10:
resolution: {integrity: sha512-KepLsg4dU12hryUO7bp/axHAKvwGOCV0sGloQtpagJ12ai+ojVDqkeGSiRX1zlq+kjIMZ1t7gpze+26QqtdGqw==}
- dev: true
/regenerator-transform/0.15.0:
resolution: {integrity: sha512-LsrGtPmbYg19bcPHwdtmXwbW+TqNvtY4riE3P83foeHRroMbH6/2ddFBfab3t7kbzc7v7p4wbkIecHImqt0QNg==}
@@ -3675,6 +3844,10 @@ packages:
webpack: 5.74.0_webpack-cli@4.10.0
dev: true
+ /style-mod/4.0.0:
+ resolution: {integrity: sha512-OPhtyEjyyN9x3nhPsu76f52yUGXiZcgvsrFVtvTkyGRQJ0XK+GPc6ov1z+lRpbeabka+MYEQxOYRnt5nF30aMw==}
+ dev: false
+
/supports-color/5.5.0:
resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==}
engines: {node: '>=4'}
@@ -3827,6 +4000,10 @@ packages:
engines: {node: '>= 0.8'}
dev: true
+ /w3c-keyname/2.2.6:
+ resolution: {integrity: sha512-f+fciywl1SJEniZHD6H+kUO8gOnwIr7f4ijKA6+ZvJFjeGi1r4PDLl53Ayud9O/rk64RqgoQine0feoeOU0kXg==}
+ dev: false
+
/watchpack/2.4.0:
resolution: {integrity: sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==}
engines: {node: '>=10.13.0'}
diff --git a/src/App.css b/src/App.css
index 60e8135..04306c9 100644
--- a/src/App.css
+++ b/src/App.css
@@ -1,4 +1,9 @@
App {
- margin: 1rem;
- font-family: Arial, Helvetica, sans-serif;
+ margin: 1rem auto;
+ font-family: sans-serif;
+}
+
+.code {
+ font-family: 'Courier New', Courier, monospace;
+ white-space: pre-wrap;
}
diff --git a/src/App.js b/src/App.js
index beb4bf7..061dd1b 100644
--- a/src/App.js
+++ b/src/App.js
@@ -1,7 +1,13 @@
import { useEffect, useState } from 'react';
-import './App.css';
import { createDbWorker } from 'sql.js-httpvfs';
import { debounce } from 'lodash';
+import Table from './Table';
+import './App.css';
+
+import CodeMirror from '@uiw/react-codemirror';
+import { sql, SQLite } from '@codemirror/lang-sql';
+import { historyField } from '@codemirror/commands';
+import schema from './schema.js';
// sadly there's no good way to package workers and wasm directly so you need a way to get these two URLs from your bundler.
// This is the webpack5 way to create a asset bundle of the worker and wasm:
@@ -24,28 +30,34 @@ const worker = createDbWorker(
const doQuery = (query, callback) => {
worker.then((worker) => {
- worker.db.query(query).then((results) => {
- callback(results);
- localStorage.setItem('query', query);
- }).catch((error) => {
- console.error(error);
- });
+ worker.db
+ .query(query)
+ .then((results) => {
+ callback(results);
+ localStorage.setItem('query', query);
+ })
+ .catch((error) => {
+ // TODO: Make this a bit nicer somehow...
+ callback([{ error: error.toString() }]);
+ console.error(error);
+ });
});
};
-const handleKeyUp = debounce((event, callback) => {
- callback(event.target.innerText);
+const handleOnChange = debounce((value, callback) => {
+ callback(value);
}, /*wait:*/ 1000);
+const stateFields = { history: historyField };
+
export default function App() {
const [results, setResults] = useState([]);
const [query, setQuery] = useState(
- localStorage.getItem("query") || "SELECT first_name, last_name FROM entities WHERE call_sign = 'K9FGT'"
+ localStorage.getItem('query') ||
+ "SELECT first_name as 'First Name', last_name as 'Last Name', city, state, call_sign FROM entities WHERE frn IN (SELECT frn FROM entities WHERE call_sign = 'K9FGT')"
);
- useEffect(() => {
- document.getElementById("query").innerText = query;
- }, []);
+ const serializedState = localStorage.getItem('editorState');
useEffect(() => {
doQuery(query, setResults);
@@ -53,8 +65,34 @@ export default function App() {
return (
<div className="App">
- <pre id="query" contentEditable onKeyUp={(e) => handleKeyUp(e, setQuery)}></pre>
- <pre>{JSON.stringify(results)}</pre>
+ <CodeMirror
+ value={query}
+ initialState={
+ serializedState
+ ? {
+ json: JSON.parse(serializedState || ''),
+ fields: stateFields,
+ }
+ : undefined
+ }
+ onChange={(value, viewUpdate) => {
+ localStorage.setItem('query', value);
+
+ const state = viewUpdate.state.toJSON(stateFields);
+ localStorage.setItem('editorState', JSON.stringify(state));
+
+ handleOnChange(value, setQuery);
+ }}
+ basicSetup={{ autocompletion: true }}
+ extensions={[
+ sql({
+ dialect: SQLite,
+ upperCaseKeywords: true,
+ schema: schema,
+ }),
+ ]}
+ />
+ <Table results={results} />
</div>
);
}
diff --git a/src/Table.css b/src/Table.css
new file mode 100644
index 0000000..c162ae1
--- /dev/null
+++ b/src/Table.css
@@ -0,0 +1,23 @@
+table {
+ border-collapse: collapse;
+ margin: 25px auto;
+ font-size: 0.9em;
+ font-family: sans-serif;
+ min-width: 400px;
+ box-shadow: 0 0 20px rgba(0, 0, 0, 0.15);
+}
+table thead tr {
+ background-color: #119dc0;
+ color: #ffffff;
+ text-align: left;
+}
+table th,
+table td {
+ padding: 12px 15px;
+}
+table tbody tr {
+ border-bottom: 1px solid #dddddd;
+}
+table tbody tr:nth-of-type(even) {
+ background-color: #f3f3f3;
+}
diff --git a/src/Table.js b/src/Table.js
new file mode 100644
index 0000000..2935f0b
--- /dev/null
+++ b/src/Table.js
@@ -0,0 +1,38 @@
+import './Table.css';
+
+export default function Table({ results }) {
+ if (results == undefined || results.length === 0) {
+ return (
+ <table>
+ <thead>
+ <tr>
+ <th>No Results</th>
+ </tr>
+ </thead>
+ </table>
+ );
+ }
+
+ return (
+ <table>
+ <thead>
+ <tr>
+ {Object.keys(results[0]).map((column) => (
+ <th key={column}>{column}</th>
+ ))}
+ </tr>
+ </thead>
+ <tbody>
+ {results.map((row) => {
+ return (
+ <tr>
+ {Object.keys(row).map((key) => {
+ return <td key={key}>{row[key]}</td>;
+ })}
+ </tr>
+ );
+ })}
+ </tbody>
+ </table>
+ );
+}
diff --git a/src/schema.js b/src/schema.js
new file mode 100644
index 0000000..8474b51
--- /dev/null
+++ b/src/schema.js
@@ -0,0 +1,168 @@
+const schema = {
+ amateurs: [
+ 'record_type',
+ 'unique_system_identifier',
+ 'uls_file_number',
+ 'ebf_number',
+ 'call_sign',
+ 'operator_class',
+ 'group_code',
+ 'region_code',
+ 'trustee_call_sign',
+ 'trustee_indicator',
+ 'physician_certification',
+ 've_signature',
+ 'systematic_call_sign_change',
+ 'vanity_call_sign_change',
+ 'vainty_relationship',
+ 'previous_call_sign',
+ 'previous_operator_class',
+ 'trustee_name',
+ ],
+ comments: [
+ 'record_type',
+ 'unique_system_identifier',
+ 'uls_file_number',
+ 'call_sign',
+ 'comment_date',
+ 'description',
+ 'status_code',
+ 'status_date',
+ ],
+ entities: [
+ 'record_type',
+ 'unique_system_identifier',
+ 'uls_file_number',
+ 'ebf_number',
+ 'call_sign',
+ 'entity_type',
+ 'licensee_id',
+ 'entity_name',
+ 'first_name',
+ 'mi',
+ 'last_name',
+ 'suffix',
+ 'phone',
+ 'fax',
+ 'email',
+ 'street_address',
+ 'city',
+ 'state',
+ 'zip_code',
+ 'po_box',
+ 'attention_line',
+ 'sgin',
+ 'frn',
+ 'applicant_type_code',
+ 'applicant_type_other',
+ 'status_code',
+ 'status_date',
+ 'lic_category_code',
+ 'linked_license_id',
+ 'linked_callsign',
+ ],
+ headers: [
+ 'record_type',
+ 'unique_system_identifier',
+ 'uls_file_number',
+ 'ebf_number',
+ 'call_sign',
+ 'license_status',
+ 'radio_service_code',
+ 'grant_date',
+ 'expired_date',
+ 'cancellation_date',
+ 'eligibility_rule_number',
+ 'reserved',
+ 'alien',
+ 'alien_government',
+ 'alien_corporation',
+ 'alien_officer',
+ 'alien_control',
+ 'revoked',
+ 'convicted',
+ 'adjudged',
+ 'reserved2',
+ 'common_carrier',
+ 'non_common_carrier',
+ 'private_comm',
+ 'fixed',
+ 'mobile',
+ 'radiolocation',
+ 'satellite',
+ 'developmental_or_sta',
+ 'interconnected_service',
+ 'certifier_first_name',
+ 'certifier_mi',
+ 'certifier_last_name',
+ 'certifier_suffix',
+ 'certifier_title',
+ 'gender',
+ 'african_american',
+ 'native_american',
+ 'hawaiian',
+ 'asian',
+ 'white',
+ 'ethnicity',
+ 'effective_date',
+ 'last_action_date',
+ 'auction_id',
+ 'reg_stat_broad_serv',
+ 'band_manager',
+ 'type_serv_broad_serv',
+ 'alien_ruling',
+ 'licensee_name_change',
+ 'whitespace_ind',
+ 'additional_cert_choice',
+ 'additional_cert_answer',
+ 'discontinuation_ind',
+ 'regulatory_compliance_ind',
+ 'eligibility_cert_900',
+ 'transition_plan_cert_900',
+ 'return_spectrum_cert_900',
+ 'payment_cert_900',
+ ],
+ history: [
+ 'record_type',
+ 'unique_system_identifier',
+ 'uls_file_number',
+ 'call_sign',
+ 'log_date',
+ 'code',
+ ],
+ license_attachments: [
+ 'record_type',
+ 'unique_system_identifier',
+ 'call_sign',
+ 'attachment_code',
+ 'attachment_description',
+ 'attachment_date',
+ 'attachment_file_name',
+ 'action_performed',
+ ],
+ special_conditions: [
+ 'record_type',
+ 'unique_system_identifier',
+ 'uls_file_number',
+ 'ebf_number',
+ 'call_sign',
+ 'special_conditions_type',
+ 'special_conditions_code',
+ 'status_code',
+ 'status_date',
+ ],
+ special_conditions_free_form: [
+ 'record_type',
+ 'unique_system_identifier',
+ 'uls_file_number',
+ 'ebf_number',
+ 'call_sign',
+ 'license_free_form_type',
+ 'unique_license_free_form_identifier',
+ 'sequence_number',
+ 'license_free_form_condition',
+ 'status_code',
+ 'status_date',
+ ],
+};
+export default schema;