diff --git a/apps/nextjs/lib/bloodScan/analyzeBloodScan.txt b/apps/nextjs/lib/bloodScan/analyzeBloodScan.txt new file mode 100644 index 000000000..8a620e99c --- /dev/null +++ b/apps/nextjs/lib/bloodScan/analyzeBloodScan.txt @@ -0,0 +1,141 @@ +// TODO + +// pages/api/bloodMarkersExtraction.ts +import { NextApiRequest, NextApiResponse } from 'next'; +import { OpenAIApi, Configuration } from 'openai'; +import pdf from 'pdf-parse'; +import fs from 'fs'; +import { fromBuffer } from 'pdf2pic'; +import axios from 'axios'; +import { getBloodScanPrompt } from './bloodScanPrompt'; + + apiKey: process.env.OPENAI_API_KEY, +}); +const openai = new OpenAIApi(configuration); + +const prompt = getBloodScanPrompt(); + +export default async function handler(req: NextApiRequest, res: NextApiResponse) { + if (req.method === 'POST') { + try { + const { bloodReportURL } = req.body; + const response = await axios.get(bloodReportURL, { responseType: 'arraybuffer' }); + const text = await extractTextFromPDF(response); + const result = text !== '' ? await extractBloodParamsWithGPT3(text) : await performOCRWithGPT4(await convertPdfToImages(response)); + res.status(200).json(result); + } catch (error) { + console.error('Error processing blood markers extraction:', error); + res.status(500).json({ error: 'An error occurred' }); + } + } else { + res.status(405).json({ error: 'Method not allowed' }); + } +} + +async function performOCRWithGPT4(base64Images: string[]) { + try { + const messages = [ + { + role: 'user', + content: [ + { + type: 'text', + text: prompt, + }, + ...base64Images.map((base64Image) => ({ + type: 'image_url', + image_url: { + url: `data:image/png;base64,${base64Image}`, + detail: 'high', + }, + })), + ], + }, + ]; + + const response = await openai.createChatCompletion({ + model: 'gpt-4-vision-preview', + messages: messages as any, + max_tokens: 3000, + }); + + const data = JSON.parse(response.data.choices[0].message.content.trim().slice(7, -3).trim()); + console.log('GPT4 response: ' + JSON.stringify(data)); + return data; + } catch (error) { + console.error('Error performing OCR with GPT-4 Vision:', error); + throw error; + } +} + +async function extractBloodParamsWithGPT3(text: string) { + try { + const conversation = [ + { role: 'system', content: 'You are a helpful assistant.' }, + { role: 'user', content: text }, + { + role: 'assistant', + content: prompt, + }, + ]; + + const response = await openai.createChatCompletion({ + model: 'gpt-4-1106-preview', + messages: conversation as any, + max_tokens: 3000, + }); + + const data = JSON.parse(response.data.choices[0].message.content.trim()); + console.log('GPT4 highlighted response: ' + JSON.stringify(data)); + return data; + } catch (error) { + console.error('Error:', error); + throw error; + } +} + +async function extractTextFromPDF(response: axios.AxiosResponse) { + try { + const data = await pdf(response.data); + return data.text.trim(); + } catch (error) { + console.error('Error fetching or processing PDF:', error.message); + throw error; + } +} + +async function convertPdfToImages(response: axios.AxiosResponse) { + try { + const pdfBuffer = Buffer.from(response.data); + const options = { + density: 900, + quality: 100, + format: 'png', + height: 4400, + preserveAspectRatio: true, + }; + const pdf2pic = fromBuffer(pdfBuffer, options); + let page = 1; + const base64Images: string[] = []; + let path: string; + + while (true) { + try { + const result = await pdf2pic(page); + path = result.path; + const imageBuffer = fs.readFileSync(result.path); + const base64Data = imageBuffer.toString('base64'); + base64Images.push(base64Data); + page++; + } catch (error) { + break; + } + } + + fs.unlinkSync(path); + return base64Images; + } catch (error) { + console.error('Error downloading PDF:'); + throw error; + } +} diff --git a/apps/nextjs/lib/bloodScan/bloodScanPrompt.ts b/apps/nextjs/lib/bloodScan/bloodScanPrompt.ts new file mode 100644 index 000000000..eae6b18d9 --- /dev/null +++ b/apps/nextjs/lib/bloodScan/bloodScanPrompt.ts @@ -0,0 +1,255 @@ +const parameters = [ + "AAMY", "AFP", "ALB", "ALP", "ALT", "AST", "ATLYMPH", "BASO%", "BILID", "BILIT", "BUN", + "CA", "CHOLT", "CL", "CREA", "EOS%", "ESR", "FERR", "GGT", "GLC", "GLOBT", "HCT", "HDL", + "HGB", "HGBA1C", "IRON", "K+", "LDL", "LYMPH%", "MCH", "MCHC", "MCV", "MONO%", "MPV", + "NA+", "NEUTR%", "P", "PDW", "PLT", "PROT", "RBC", "RDW", "TRIG", "UA", "WBC", +]; + +export function getBloodScanPrompt() { + return `Extract blood parameters, their values, range of values, + and the unit in which each parameter is measured. Ensure utmost precision as we require 100% accuracy. + Return the response in JSON format with keys being the English abbreviations of the parameter names. + Each value should be represented as a map with keys 'value,' 'range,' and 'unit.' + Only include blood parameters listed in ${parameters}. Do not return anything other than JSON. + Here is an example of a response: + """ + { + "AAMY": { + "value": 50.0, + "range": "25.0 - 125.0", + "unit": "u/l" + }, + "AFP": { + "value": 3.0, + "range": "0.0 - 8.3", + "unit": "u/ml" + }, + "ALB": { + "value": 4.6, + "range": "3.6 - 5.1", + "unit": "g/l" + }, + "ALP": { + "value": 50.0, + "range": "36 - 130", + "unit": "IU/L" + }, + "ALT": { + "value": 21.0, + "range": "9 - 46", + "unit": "IU/L" + }, + "AST": { + "value": 26.0, + "range": "10 - 40", + "unit": "IU/L" + }, + "ATLYMPH": { + "value": 3.0, + "range": "0 - 12", + "unit": "%" + }, + "BASO%": { + "value": 0.7, + "range": "0.0 - 1.0", + "unit": "%" + }, + "BILID": { + "value": 3.0, + "range": "0.0 - 6.84", + "unit": "umol/l" + }, + "BILIT": { + "value": 1.0, + "range": "0.60 - 1.35", + "unit": "umol/l" + }, + "BUN": { + "value": 4.0, + "range": "2.5 - 6.43", + "unit": "mmol/l" + }, + "CA": { + "value": 2.3, + "range": "2.05 - 2.64", + "unit": "mmol/l" + }, + "CHOLT": { + "value": 120.0, + "range": "100 - 110", + "unit": "mmol/l" + }, + "CL": { + "value": 108.0, + "range": "98 - 110", + "unit": "mmol/l" + }, + "CREA": { + "value": 50.0, + "range": "45.0 - 90.0", + "unit": "umol/l" + }, + "EOS%": { + "value": 4.0, + "range": "1.0 - 4.0", + "unit": "%" + }, + "ESR": { + "value": 15.0, + "range": "0.0 - 30.0", + "unit": "mm/hr" + }, + "FERR": { + "value": 300.0, + "range": "24.72 - 689.83", + "unit": "ug/l" + }, + "GGT": { + "value": 20.0, + "range": "5.0 - 40.0", + "unit": "u/l" + }, + "GLC": { + "value": 4.0, + "range": "3.61 - 5.55", + "unit": "mmol/l" + }, + "GLOBT": { + "value": 30.0, + "range": "23.0 - 35.0", + "unit": "g/l" + }, + "HCT": { + "value": 41.0, + "range": "38.5 - 50.0", + "unit": "%" + }, + "HDL": { + "value": 2.0, + "range": "1.0 - 2.7", + "unit": "mmol/l" + }, + "HGB": { + "value": 130.0, + "range": "120.0 - 160.0", + "unit": "g/l" + }, + "HGBA1C": { + "value": 4.0, + "range": "3.9 - 5.3", + "unit": "%" + }, + "IRON": { + "value": 10.0, + "range": "6.63 - 25.97", + "unit": "umol/l" + }, + "K+": { + "value": 4.0, + "range": "3.5 - 5.3", + "unit": "mmol/l" + }, + "LDL": { + "value": 3.0, + "range": "2.0 - 5.3", + "unit": "mmol/l" + }, + "LYMPH%": { + "value": 34.8, + "range": "20.0 - 40.0", + "unit": "%" + }, + "MCH": { + "value": 31.0, + "range": "27.0 - 33.0", + "unit": "pg" + }, + "MCHC": { + "value": 330.0, + "range": "320.0 - 360.0", + "unit": "g/l" + }, + "MCV": { + "value": 96.0, + "range": "80.0 - 100.0", + "unit": "fl" + }, + "MONO%": { + "value": 7.4, + "range": "2.0 - 8.0", + "unit": "%" + }, + "MPV": { + "value": 8.0, + "range": "7.5 - 12.5", + "unit": "fl" + }, + "NA+": { + "value": 136.0, + "range": "135 - 146", + "unit": "mmol/l" + }, + "NEUTR%": { + "value": 60.0, + "range": "55.0 - 73.0", + "unit": "%" + }, + "P": { + "value": 1.0, + "range": "0.97 - 1.45", + "unit": "mmol/l" + }, + "PDW": { + "value": 13.0, + "range": "10.0 - 17.9", + "unit": "%" + }, + "PLT": { + "value": 350.0, + "range": "140 - 400", + "unit": "thousand/ul" + }, + "PROT": { + "value": 70.0, + "range": "60.0 - 80.0", + "unit": "g/l" + }, + "RBC": { + "value": 4.2, + "range": "4.20 - 5.80", + "unit": "x10e9/L" + }, + "RDW": { + "value": 12.6, + "range": "11.0 - 15.0", + "unit": "%" + }, + "TRIG": { + "value": 1.3, + "range": "0.85 - 1.84", + "unit": "mmol/l" + }, + "UA": { + "value": 0.3, + "range": "0.12 - 0.42", + "unit": "mmol/l" + }, + "WBC": { + "value": 5.5, + "range": "4.1 - 10.9", + "unit": "x10e9/L" + } + } + """ + Values and ranges should never contain words and letters, only numbers and characters like ">" and "<". + Most of the blood tests are structured in a way where all the information for one parameter is horizontally in the same row but in different columns so make sure to not mix them up since they are all close together and its easy to read a parameter from another row. + Be very careful with differentiating between the number 5 and 8. + Pay close attention to dots as they hold significant importance. Their presence or absence, and correct placement, can greatly impact the outcome. + Be exceptionally precise and avoid speculation. If uncertain about a value, range, or unit in the context of blood test analysis, refrain from providing information rather than presenting inaccurate details. Achieving accuracy is paramount in this task. + Ensure that there are no keys in response that arent in ${parameters}. + Additionally, the value must be specific and cannot be checked, but the unit must match the example provided. + The acceptable range should resemble the example provided, though it need not be an exact match, as it may vary depending on the laboratory. + The range should include numbers and special characters, excluding words and letters. For instance, if the example range is 'recommendation < 5.0,' ensure that the provided range does not include the word 'recommendation' but only '< 5.0.' + When assessing the similarity of the range, consider the units; for example, 0.0 - 5.5mmol/l is equivalent to 0.0 - 0.0055mol/l. + This example illustrates the expected structure, and no additional text beyond the JSON format is required.`; +} diff --git a/apps/nextjs/lib/dateTimeWithTimezone.ts b/apps/nextjs/lib/dateTimeWithTimezone.ts index 89a1aa79b..a5246ed15 100644 --- a/apps/nextjs/lib/dateTimeWithTimezone.ts +++ b/apps/nextjs/lib/dateTimeWithTimezone.ts @@ -4,11 +4,9 @@ export function getUtcDateTimeWithTimezone() { return new Date(date.getTime() - timezoneOffset * 60000).toISOString(); } -export function convertToUTC(localDateTime: string, utcDateTimeWithTimezone: string) { +export function convertToUTC(localDateTime: string, timezoneOffset: number) { const localDate = new Date(localDateTime); - const timezoneOffset = parseInt(utcDateTimeWithTimezone.split(':')[0]); - const utcDate = new Date(localDate.getTime() + timezoneOffset * 60 * 60 * 1000); - return utcDate.toISOString(); + return new Date(localDate.getTime() + timezoneOffset * 60000).toISOString(); } export function throwErrorIfDateInFuture(utcDateTime: string) { diff --git a/apps/nextjs/lib/fdaiAgent.ts b/apps/nextjs/lib/fdaiAgent.ts new file mode 100644 index 000000000..91b654ac1 --- /dev/null +++ b/apps/nextjs/lib/fdaiAgent.ts @@ -0,0 +1,45 @@ +import {textCompletion} from "@/lib/llm"; + +export async function foodOrDrugCostBenefitAnalysis(foodOrDrug: string) { + const prompt = `Conduct a comprehensive cost-benefit analysis on the + regular consumption of "${foodOrDrug}", including both positive and negative effects. In your analysis, consider the following: + +Health Benefits: + +Summarize the major health benefits associated with the consumption of [insert food or drug here], based on existing research. +Discuss the potential mechanisms by which [insert food or drug here] provides these health benefits. +Health Risks: + +Identify and summarize the potential health risks and side effects linked to the regular consumption of [insert food or drug here]. +Discuss the severity and likelihood of these risks, referencing relevant studies. +Cost Analysis: + +Estimate the economic cost of regularly consuming [insert food or drug here], considering factors like price, accessibility, and potential healthcare costs due to side effects. +Quality of Life: + +Analyze how the regular consumption of [insert food or drug here] might impact an individual's quality of life, both positively and negatively. +DALYs (Disability-Adjusted Life Years): + +Provide an estimated range of potential change in DALYs for the average person who regularly consumes [insert food or drug here]. +Discuss the level of uncertainty in these estimates and the factors contributing to this uncertainty. +Overall Assessment: + +Conclude with an overall assessment of whether the benefits of consuming [insert food or drug here] outweigh the risks and costs. +Include recommendations for specific populations (e.g., age groups, people with certain health conditions) who might benefit most or least from regular consumption of [insert food or drug here]. +Please base your analysis on your available knowledge of existing research, and clearly state the degree of your uncertainty in each aspect of the analysis.`; + return await textCompletion(prompt, "text"); +} + +export async function safeUnapprovedDrugs(){ + const prompt = `Provide a comprehensive json array of + the names of all treatments + that have been proven to be safe in the majority of studies but are unavailable + due to patent expiration or lack of financial incentive due to regulatory burden. + + Only include drugs that are not available to patients. + List as many as you can. + + `; + return await textCompletion(prompt, "json_object"); +} + diff --git a/apps/nextjs/lib/llm.ts b/apps/nextjs/lib/llm.ts index 0ba5e3d04..78d262e53 100644 --- a/apps/nextjs/lib/llm.ts +++ b/apps/nextjs/lib/llm.ts @@ -1,5 +1,5 @@ import OpenAI from 'openai'; -import {getUtcDateTime} from "@/lib/dateTimeWithTimezone"; +import {convertToLocalDateTime} from "@/lib/dateTimeWithTimezone"; // Create an OpenAI API client (that's edge-friendly!) const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY || '', @@ -33,10 +33,12 @@ export async function textCompletion(promptText: string, returnType: "text" | "j return response.choices[0].message.content; } -export async function getDateTimeFromStatement(statement: string): Promise { - const currentDate = getUtcDateTime(); +export async function getDateTimeFromStatementInUserTimezone(statement: string, + utcDateTime: string, + timeZoneOffset: number): Promise { + const localDateTime = convertToLocalDateTime(utcDateTime, timeZoneOffset); const promptText = ` - estimate the date and time of the user statement based on the current date and time ${currentDate} + estimate the date and time of the user statement based on the user's current date and time ${localDateTime} and the following user statement: \`\`\` ${statement} diff --git a/apps/nextjs/lib/text2measurements.ts b/apps/nextjs/lib/text2measurements.ts index 6f1549a69..e4c71d028 100644 --- a/apps/nextjs/lib/text2measurements.ts +++ b/apps/nextjs/lib/text2measurements.ts @@ -1,23 +1,17 @@ import {Measurement} from "@/types/models/Measurement"; -import {getDateTimeFromStatement, textCompletion} from "@/lib/llm"; +import {getDateTimeFromStatementInUserTimezone, textCompletion} from "@/lib/llm"; import {getUserId} from "@/lib/getUserId"; import {postMeasurements} from "@/lib/dfda"; import { - convertToLocalDateTime, - throwErrorIfDateInFuture + convertToLocalDateTime, convertToUTC, } from "@/lib/dateTimeWithTimezone"; export function generateText2MeasurementsPrompt(statement: string, - utcDateTime: string, + currentUtcDateTime: string, timeZoneOffset: number): string { - if(!utcDateTime) { - const now = new Date(); - utcDateTime = now.toISOString().slice(0, 19); - } - throwErrorIfDateInFuture(utcDateTime); - const localDateTime = convertToLocalDateTime(utcDateTime, timeZoneOffset); - const localDate = utcDateTime.split('T')[0]; + const currentLocalDateTime = convertToLocalDateTime(currentUtcDateTime, timeZoneOffset); + const currentLocalDate = currentUtcDateTime.split('T')[0]; return ` You are a service that translates user requests into an array of JSON objects of type "Measurement" according to the following TypeScript definitions: @@ -133,19 +127,19 @@ export interface Measurement { // For example, if the answer is "I took 5 mg of NMN", then this value is 5. // For example, if the answer is "I have been feeling very tired and fatigued today", you would return two measurements // with the value 5 like this: - // {variableName: "Tiredness", value: 5, unitName: "1 to 5 Rating", startAt: "${localDate}T00:00:00", endAt: "${localDate}T23:59:59", combinationOperation: "MEAN", variableCategoryName: "Symptoms"} - // {variableName: "Fatigue", value: 5, unitName: "1 to 5 Rating", startAt: "${localDate}T00:00:00", endAt: "${localDate}T23:59:59", combinationOperation: "MEAN", variableCategoryName: "Symptoms"} + // {variableName: "Tiredness", value: 5, unitName: "1 to 5 Rating", startAt: "${currentLocalDate}T00:00:00", endAt: "${currentLocalDate}T23:59:59", combinationOperation: "MEAN", variableCategoryName: "Symptoms"} + // {variableName: "Fatigue", value: 5, unitName: "1 to 5 Rating", startAt: "${currentLocalDate}T00:00:00", endAt: "${currentLocalDate}T23:59:59", combinationOperation: "MEAN", variableCategoryName: "Symptoms"} // For example, if the answer is "I have been having trouble concentrating today", then this value is 1 and the object - // would be {variableName: "Concentration", value: 1, unitName: "1 to 5 Rating", startAt: "${localDate}T00:00:00", endAt: "${localDate}T23:59:59", combinationOperation: "MEAN", variableCategoryName: "Symptoms"} + // would be {variableName: "Concentration", value: 1, unitName: "1 to 5 Rating", startAt: "${currentLocalDate}T00:00:00", endAt: "${currentLocalDate}T23:59:59", combinationOperation: "MEAN", variableCategoryName: "Symptoms"} // For example, if the answer is "I also took magnesium 200mg, Omega3 one capsule 500mg", then the measurements would be: - // {variableName: "Magnesium", value: 200, unitName: "Milligrams", startAt: "${localDate}T00:00:00", endAt: "${localDate}T23:59:59", combinationOperation: "SUM", variableCategoryName: "Treatments"} - // {variableName: "Omega3", value: 500, unitName: "Milligrams", startAt: "${localDate}T00:00:00", endAt: "${localDate}T23:59:59", combinationOperation: "SUM", variableCategoryName: "Treatments"} + // {variableName: "Magnesium", value: 200, unitName: "Milligrams", startAt: "${currentLocalDate}T00:00:00", endAt: "${currentLocalDate}T23:59:59", combinationOperation: "SUM", variableCategoryName: "Treatments"} + // {variableName: "Omega3", value: 500, unitName: "Milligrams", startAt: "${currentLocalDate}T00:00:00", endAt: "${currentLocalDate}T23:59:59", combinationOperation: "SUM", variableCategoryName: "Treatments"} // (I just used the current date in those examples, but you should use the correct date if the user specifies a different date or time range.) unitName: UnitName; // unitName is the unit of the treatment, symptom, food, drink, etc. // For example, if the answer is "I took 5 mg of NMN", then this unitName is "Milligrams". - startAt: string; // startAt should be the local datetime the measurement was taken in the format "YYYY-MM-DDThh:mm:ss" inferred from the USER STATEMENT relative to and sometime before the current local datetime ${localDateTime}. - endAt: string|null; // If a time range is suggested, then endAt should be the end of that period. It should also be in the format "YYYY-MM-DDThh:mm:ss" and should not be in the future relative to the current time ${localDateTime} . + startAt: string; // startAt should be the local datetime the measurement was taken in the format "YYYY-MM-DDThh:mm:ss" inferred from the USER STATEMENT relative to and sometime before the current local datetime ${currentLocalDateTime}. + endAt: string|null; // If a time range is suggested, then endAt should be the end of that period. It should also be in the format "YYYY-MM-DDThh:mm:ss" and should not be in the future relative to the current time ${currentLocalDateTime} . combinationOperation: "SUM" | "MEAN"; // combinationOperation is the operation used to combine multiple measurements of the same variableName variableCategoryName: VariableCategoryName; // variableCategoryName is the category of the variableName // For example, if the answer is "I took 5 mg of NMN", then this variableCategoryName is "Treatments". @@ -179,7 +173,7 @@ export type Symptom = Measurement & { unitName: '/5'; }; -Remember, startAt and endAt should be in the format "YYYY-MM-DDThh:mm:ss" and should not be in the future relative to the current time ${localDateTime}. +Remember, startAt and endAt should be in the format "YYYY-MM-DDThh:mm:ss" and should not be in the future relative to the current time ${currentLocalDateTime}. USER STATEMENT TO CONVERT TO AN ARRAY OF MEASUREMENTS: """ @@ -191,25 +185,18 @@ The following is the user request translated into a JSON object with 2 spaces of } export async function text2measurements(statement: string, - utcDateTime: string, + currentUtcDateTime: string, timeZoneOffset: number): Promise { - const promptText = generateText2MeasurementsPrompt(statement, utcDateTime, timeZoneOffset); + const promptText = generateText2MeasurementsPrompt(statement, currentUtcDateTime, timeZoneOffset); const str = await textCompletion(promptText, "json_object"); - const dateTime = await getDateTimeFromStatement(statement); + const localDateTime = await getDateTimeFromStatementInUserTimezone(statement, + currentUtcDateTime, timeZoneOffset); + const utcDateTimeFromStatement = convertToUTC(localDateTime, timeZoneOffset); let json = JSON.parse(str); - if(!Array.isArray(str)){ - json = [json]; - } + if(!Array.isArray(str)){json = [json];} const measurements: Measurement[] = []; json.forEach((measurement: Measurement) => { - // Convert the startAt to UTC based on the timezone from the utcDateTime - measurement.startAt = dateTime; - // replace with the current time if greater - const now = new Date().toISOString(); - if(measurement.startAt > now){ - console.error(`startAt is in the future: ${measurement.startAt}`); - measurement.startAt = now; - } + measurement.startAt = utcDateTimeFromStatement; measurements.push(measurement); }); const userId = await getUserId(); diff --git a/apps/nextjs/tests/fdai.test.ts b/apps/nextjs/tests/fdai.test.ts new file mode 100644 index 000000000..da4231bdf --- /dev/null +++ b/apps/nextjs/tests/fdai.test.ts @@ -0,0 +1,16 @@ +/** + * @jest-environment node + */ +import {foodOrDrugCostBenefitAnalysis, safeUnapprovedDrugs} from "@/lib/fdaiAgent"; +beforeAll(async () => { +}); +describe("FDAi Tests", () => { + it("cost-benefit analysis", async () => { + const result = await foodOrDrugCostBenefitAnalysis("NMN"); + console.log(result); + }, 45000); + it("safe unapproved drugs", async () => { + const safeUnapproved = await safeUnapprovedDrugs(); + console.log(safeUnapproved); + }, 45000); +}); diff --git a/docs/api-docs/guides/oauth-integration.mdx b/docs/api-docs/guides/oauth-integration.mdx new file mode 100644 index 000000000..a60d4bd23 --- /dev/null +++ b/docs/api-docs/guides/oauth-integration.mdx @@ -0,0 +1,148 @@ +--- +title: Authenticate with OAuth +description: Learn how to obtain an access token using OAuth 2.0 to interact with the dFDA API. +--- +# Getting an Access Token via OAuth + +This guide explains how to obtain an access token using OAuth 2.0 to interact with the dFDA API. + +The examples are in Node.js, but the same principles apply to any programming language. + +## Prerequisites + +- Node.js installed on your system +- Your client ID and client secret from https://builder.dfda.earth +- A server capable of handling OAuth redirects + +## Setting Up Your Environment + +1. Install required packages: + +```bash +npm install dotenv express node-fetch +``` + +2. Create a `.env` file in your project root: + +``` +DFDA_CLIENT_ID=your_client_id_here +DFDA_CLIENT_SECRET=your_client_secret_here +REDIRECT_URI=http://localhost:3000/callback +``` + +Replace the values with your actual client ID, client secret, and redirect URI. + +## Implementing OAuth Flow + +### Step 1: Redirect to Authorization Page + +Create a route that redirects the user to the dFDA authorization page: + +```javascript +require('dotenv').config(); +const express = require('express'); +const app = express(); + +app.get('/login', (req, res) => { + const authUrl = `https://safe.dfda.earth/oauth/authorize?client_id=${process.env.DFDA_CLIENT_ID}&redirect_uri=${encodeURIComponent(process.env.REDIRECT_URI)}&response_type=code`; + res.redirect(authUrl); +}); + +app.listen(3000, () => console.log('Server running on port 3000')); +``` + +### Step 2: Handle the Callback + +Create a route to handle the callback from dFDA after user authorization: + +```javascript +const fetch = require('node-fetch'); + +app.get('/callback', async (req, res) => { + const { code } = req.query; + + if (!code) { + return res.status(400).send('Authorization code not received'); + } + + try { + const tokenResponse = await fetch('https://safe.dfda.earth/oauth/token', { + method: 'POST', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + }, + body: new URLSearchParams({ + grant_type: 'authorization_code', + client_id: process.env.DFDA_CLIENT_ID, + client_secret: process.env.DFDA_CLIENT_SECRET, + code: code, + redirect_uri: process.env.REDIRECT_URI, + }), + }); + + const tokenData = await tokenResponse.json(); + + if (tokenData.access_token) { + // Store the access token securely (e.g., in a database) + // For this example, we're just sending it back to the client + res.json({ access_token: tokenData.access_token }); + } else { + res.status(400).json({ error: 'Failed to obtain access token' }); + } + } catch (error) { + console.error('Error obtaining access token:', error); + res.status(500).json({ error: 'Internal server error' }); + } +}); +``` + +## Using the Access Token + +Once you have obtained the access token, you can use it to make authenticated requests to the dFDA API: + +```javascript +async function makeAuthenticatedRequest(accessToken) { + const response = await fetch('https://safe.dfda.earth/api/v1/user', { + method: 'GET', + headers: { + 'accept': 'application/json', + 'Authorization': `Bearer ${accessToken}`, + }, + }); + + return response.json(); +} +``` + +## Refreshing the Access Token + +Access tokens expire after a certain period. To continue using the API, you'll need to refresh the token using the refresh token provided along with the access token: + +```javascript +async function refreshAccessToken(refreshToken) { + const response = await fetch('https://safe.dfda.earth/oauth/token', { + method: 'POST', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + }, + body: new URLSearchParams({ + grant_type: 'refresh_token', + client_id: process.env.DFDA_CLIENT_ID, + client_secret: process.env.DFDA_CLIENT_SECRET, + refresh_token: refreshToken, + }), + }); + + return response.json(); +} +``` + +Remember to securely store both the access token and refresh token, and implement a mechanism to refresh the access token when it expires. + +## Security Considerations + +- Never expose your client secret in client-side code. +- Store access tokens and refresh tokens securely, preferably encrypted in your database. +- Use HTTPS for all OAuth-related communications. + +By following this guide, you should be able to implement OAuth 2.0 authentication with the dFDA API using Node.js. This allows your application to securely obtain and use access tokens for making authenticated requests to the API. diff --git a/docs/api-docs/mint.json b/docs/api-docs/mint.json index dbc8ae080..353d6fc21 100644 --- a/docs/api-docs/mint.json +++ b/docs/api-docs/mint.json @@ -175,7 +175,7 @@ ], "footerSocials": { "twitter": "https://twitter.com/FDADAO", - "github": "https://github.com/FDAi", + "github": "https://github.com/FDA-AI/FDAi", "linkedin": "https://www.linkedin.com/curedao" } } diff --git a/docs/images/fdai-banner.png b/docs/images/fdai-banner.png new file mode 100644 index 000000000..9db3ab223 Binary files /dev/null and b/docs/images/fdai-banner.png differ diff --git a/libs/db-schema/postgres/mysql2pg.js b/libs/db-schema/postgres/mysql2pg.js new file mode 100644 index 000000000..989570cbb --- /dev/null +++ b/libs/db-schema/postgres/mysql2pg.js @@ -0,0 +1,101 @@ +const mysql = require('mysql2/promise'); +const { Client } = require('pg'); +const fs = require('fs'); +const path = require('path'); +const dotenv = require('dotenv'); +dotenv.config({ path: path.join(__dirname, '..', '.env') }); + +// MySQL connection configuration +const mysqlConfig = { + host: process.env.MYSQL_HOST, + user: process.env.MYSQL_USER, + password: process.env.MYSQL_PASSWORD, + database: process.env.MYSQL_DATABASE, +}; + +// PostgreSQL connection configuration +const postgresConfig = { + host: process.env.POSTGRES_HOST, + user: process.env.POSTGRES_USER, + password: process.env.POSTGRES_PASSWORD, + database: process.env.POSTGRES_DATABASE, +}; +async function exportMySQLToPostgreSQL() { + const mysqlConnection = await mysql.createConnection(mysqlConfig); + const postgresClient = new Client(postgresConfig); + await postgresClient.connect(); + + // Define an array of user ids that you want to import + const userIds = [1]; // replace with your user ids + + try { + // Get the list of tables in the MySQL database + const [tables] = await mysqlConnection.query('SHOW TABLES'); + + for (const table of tables) { + const tableName = table[`Tables_in_${mysqlConfig.database}`]; + + // Check if the table has a user_id field + const [fields] = await mysqlConnection.query(`DESCRIBE ${tableName}`); + const hasUserIdField = fields.some(field => field.Field === 'user_id'); + + // Get the table structure and create the table in PostgreSQL + const [tableInfo] = await mysqlConnection.query(`SHOW CREATE TABLE ${tableName}`); + const createTableQuery = tableInfo[0]['Create Table']; + + // Modify the create table query to be compatible with PostgreSQL + const modifiedCreateTableQuery = createTableQuery + .replace(/`/g, '"') + .replace(/ENGINE=InnoDB/g, '') + .replace(/DEFAULT CHARSET=\w+/, '') + .replace(/COLLATE=\w+/, '') + .replace(/COMMENT='.*?'/g, ''); + + await postgresClient.query(modifiedCreateTableQuery); + + // Export data from MySQL and import into PostgreSQL + let selectQuery = `SELECT * FROM ${tableName}`; + if (hasUserIdField) { + selectQuery += ` WHERE user_id IN (${userIds.join(', ')})`; + } + const [rows] = await mysqlConnection.query(selectQuery); + if (rows.length > 0) { + const columns = Object.keys(rows[0]); + const values = rows.map((row) => Object.values(row)); + + const insertQuery = ` + INSERT INTO "${tableName}" ("${columns.join('", "')}") + VALUES ${values.map((row) => `(${row.map((value) => (value === null ? 'NULL' : `'${value}'`)).join(', ')})`).join(', ')} + `; + + await postgresClient.query(insertQuery); + } + } + + // Export comments and constraints from MySQL and recreate in PostgreSQL + const [constraints] = await mysqlConnection.query(` + SELECT CONCAT( + 'ALTER TABLE ', TABLE_NAME, + ' ADD CONSTRAINT ', CONSTRAINT_NAME, + ' ', CONSTRAINT_TYPE, ' (', GROUP_CONCAT(COLUMN_NAME ORDER BY ORDINAL_POSITION), ');' + ) AS constraint_query + FROM information_schema.KEY_COLUMN_USAGE + WHERE CONSTRAINT_SCHEMA = '${mysqlConfig.database}' AND REFERENCED_TABLE_NAME IS NOT NULL + GROUP BY CONSTRAINT_NAME + `); + + for (const constraint of constraints) { + const constraintQuery = constraint.constraint_query; + await postgresClient.query(constraintQuery); + } + + console.log('Data export and import completed successfully.'); + } catch (error) { + console.error('Error during data export and import:', error); + } finally { + await mysqlConnection.end(); + await postgresClient.end(); + } +} + +exportMySQLToPostgreSQL(); diff --git a/libs/db-schema/postgres/schema.prisma b/libs/db-schema/postgres/schema.prisma new file mode 100644 index 000000000..5b694fb26 --- /dev/null +++ b/libs/db-schema/postgres/schema.prisma @@ -0,0 +1,1790 @@ +generator client { + provider = "prisma-client-js" +} + +datasource db { + provider = "postgresql" + url = env("DATABASE_URL") +} + +model global_variable_relationships { + id Int @id @default(autoincrement()) + forward_pearson_correlation_coefficient Float + onset_delay Int + duration_of_action Int + number_of_pairs Int + value_predicting_high_outcome Float + value_predicting_low_outcome Float + optimal_pearson_product Float + average_vote Float? @default(0.5) + number_of_users Int + number_of_user_variable_relationships Int + statistical_significance Float + cause_unit_id Int? @db.SmallInt + cause_changes Int + effect_changes Int + aggregate_qm_score Float + created_at DateTime @default(now()) @db.Timestamp(0) + updated_at DateTime @default(now()) @db.Timestamp(0) + status String @db.VarChar(25) + reverse_pearson_correlation_coefficient Float + predictive_pearson_correlation_coefficient Float + data_source_name String? @db.VarChar(255) + predicts_high_effect_change Int + predicts_low_effect_change Int + p_value Float + t_value Float + critical_t_value Float + confidence_interval Float + deleted_at DateTime? @db.Timestamp(0) + average_effect Float + average_effect_following_high_cause Float + average_effect_following_low_cause Float + average_daily_low_cause Float + average_daily_high_cause Float + population_trait_pearson_correlation_coefficient Float? + grouped_cause_value_closest_to_value_predicting_low_outcome Float + grouped_cause_value_closest_to_value_predicting_high_outcome Float + client_id String? @db.VarChar(255) + published_at DateTime? @db.Timestamp(0) + dfda_post_id BigInt? + cause_variable_category_id Int @db.SmallInt + effect_variable_category_id Int @db.SmallInt + interesting_variable_category_pair Boolean + newest_data_at DateTime? @db.Timestamp(0) + analysis_requested_at DateTime? @db.Timestamp(0) + reason_for_analysis String @db.VarChar(255) + analysis_started_at DateTime? @db.Timestamp(0) + analysis_ended_at DateTime? @db.Timestamp(0) + user_error_message String? + internal_error_message String? + cause_variable_id Int + effect_variable_id Int + cause_baseline_average_per_day Float + cause_baseline_average_per_duration_of_action Float + cause_treatment_average_per_day Float + cause_treatment_average_per_duration_of_action Float + effect_baseline_average Float + effect_baseline_relative_standard_deviation Float + effect_baseline_standard_deviation Float + effect_follow_up_average Float + effect_follow_up_percent_change_from_baseline Float + z_score Float + charts Json @db.Json + number_of_variables_where_best_aggregate_correlation Int + deletion_reason String? @db.VarChar(280) + record_size_in_kb Int? + is_public Boolean + slug String? @unique(map: "global_variable_relationships_slug_uindex") @db.VarChar(200) + boring Boolean? + outcome_is_a_goal Boolean? + predictor_is_controllable Boolean? + plausibly_causal Boolean? + obvious Boolean? + number_of_up_votes Int + number_of_down_votes Int + strength_level String @db.VarChar(255) + confidence_level String @db.VarChar(255) + relationship String @db.VarChar(255) + units units? @relation(fields: [cause_unit_id], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "global_variable_relationships_cause_unit_id_fk") + variable_categories_global_variable_relationships_cause_variable_category_idTovariable_categories variable_categories @relation("global_variable_relationships_cause_variable_category_idTovariable_categories", fields: [cause_variable_category_id], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "global_variable_relationships_cause_variable_category_id_fk") + variables_global_variable_relationships_cause_variable_idTovariables global_variables @relation(fields: [client_id], references: [client_id], onDelete: NoAction, onUpdate: NoAction, map: "global_variable_relationships_client_id_fk") + variable_categories_global_variable_relationships_effect_variable_category_idTovariable_categories variable_categories @relation("global_variable_relationships_effect_variable_category_idTovariable_categories", fields: [effect_variable_category_id], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "global_variable_relationships_effect_variable_category_id_fk") + correlation_causality_votes correlation_causality_votes[] + variable_relationship_usefulness_votes variable_relationship_usefulness_votes[] + user_variable_relationships user_variable_relationships[] + global_studies global_studies[] + variables_variables_best_aggregate_correlation_idToglobal_variable_relationships global_variables[] @relation("variables_best_aggregate_correlation_idToglobal_variable_relationships") + votes votes[] + variables global_variables? @relation(fields: [variablesId], references: [id]) + variablesId Int? + variables global_variables? @relation(fields: [variablesId], references: [id]) + variablesId Int? + oa_clients oa_clients? @relation(fields: [oa_clientsClient_id], references: [client_id]) + oa_clientsClient_id String? @db.VarChar(80) + + @@unique([cause_variable_id, effect_variable_id], map: "global_variable_relationships_pk") + @@unique([cause_variable_id, effect_variable_id], map: "cause_variable_id_effect_variable_id_uindex") + @@index([cause_unit_id], map: "global_variable_relationships_cause_unit_id_fk") + @@index([cause_variable_category_id], map: "global_variable_relationships_cause_variable_category_id_fk") + @@index([client_id], map: "global_variable_relationships_client_id_fk") + @@index([effect_variable_category_id], map: "global_variable_relationships_effect_variable_category_id_fk") + @@index([effect_variable_id], map: "global_variable_relationships_effect_variable_id_index") + @@index([dfda_post_id], map: "global_variable_relationships_dfda_posts_ID_fk") +} + +model cohort_studies { + id Int @id + cohort_study_statistics_id Int? + cause_variable_id Int + effect_variable_id Int + user_id BigInt + created_at DateTime @default(now()) @db.Timestamp(0) + deleted_at DateTime? @db.Timestamp(0) + analysis_parameters String? + user_study_text String? + user_title String? + study_status String @default("publish") @db.VarChar(20) + comment_status String @default("open") @db.VarChar(20) + study_password String? @db.VarChar(20) + study_images String? + updated_at DateTime @default(now()) @db.Timestamp(0) + client_id String? @db.VarChar(255) + published_at DateTime? @db.Timestamp(0) + dfda_post_id Int? + cohort_correlation_id Int? + newest_data_at DateTime? @db.Timestamp(0) + analysis_requested_at DateTime? @db.Timestamp(0) + reason_for_analysis String? @db.VarChar(255) + analysis_ended_at DateTime? @db.Timestamp(0) + analysis_started_at DateTime? @db.Timestamp(0) + internal_error_message String? @db.VarChar(255) + user_error_message String? @db.VarChar(255) + status String? @db.VarChar(25) + analysis_settings_modified_at DateTime? @db.Timestamp(0) + is_public Boolean? + sort_order Int? + slug String? @unique(map: "cohort_studies_slug_uindex") @db.VarChar(200) + variables_cohort_studies_cause_variable_idTovariables global_variables @relation("cohort_studies_cause_variable_idTovariables", fields: [cause_variable_id], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "cohort_studies_cause_variable_id_variables_id_fk") + variables_cohort_studies_effect_variable_idTovariables global_variables @relation("cohort_studies_effect_variable_idTovariables", fields: [effect_variable_id], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "cohort_studies_effect_variable_id_variables_id_fk") + dfda_users dfda_users @relation(fields: [user_id], references: [ID], onDelete: NoAction, onUpdate: NoAction, map: "cohort_studies_user_id_fk") + oa_clients oa_clients? @relation(fields: [oa_clientsClient_id], references: [client_id]) + oa_clientsClient_id String? @db.VarChar(80) + + @@unique([user_id, cause_variable_id, effect_variable_id], map: "user_cause_effect") + @@index([cause_variable_id], map: "cause_variable_id") + @@index([cause_variable_id], map: "cohort_studies_cause_variable_id") + @@index([client_id], map: "cohort_studies_client_id_fk") + @@index([effect_variable_id], map: "cohort_studies_effect_variable_id") + @@index([effect_variable_id], map: "effect_variable_id") +} + + + +model cohort_study_statistics { + id Int @id @default(autoincrement()) + cohort_study_id Int? + forward_pearson_correlation_coefficient Float + onset_delay Int + duration_of_action Int + number_of_pairs Int + value_predicting_high_outcome Float + value_predicting_low_outcome Float + optimal_pearson_product Float + average_vote Float? @default(0.5) + number_of_participants Int + statistical_significance Float + cause_unit_id Int? @db.SmallInt + cause_changes Int + effect_changes Int + Cohort_qm_score Float + created_at DateTime @default(now()) @db.Timestamp(0) + updated_at DateTime @default(now()) @db.Timestamp(0) + status String @db.VarChar(25) + reverse_pearson_correlation_coefficient Float + predictive_pearson_correlation_coefficient Float + data_source_name String? @db.VarChar(255) + predicts_high_effect_change Int + predicts_low_effect_change Int + p_value Float + t_value Float + critical_t_value Float + confidence_interval Float + deleted_at DateTime? @db.Timestamp(0) + average_effect Float + average_effect_following_high_cause Float + average_effect_following_low_cause Float + average_daily_low_cause Float + average_daily_high_cause Float + population_trait_pearson_correlation_coefficient Float? + grouped_cause_value_closest_to_value_predicting_low_outcome Float + grouped_cause_value_closest_to_value_predicting_high_outcome Float + client_id String? @db.VarChar(255) + published_at DateTime? @db.Timestamp(0) + dfda_post_id BigInt? + cause_variable_category_id Int @db.SmallInt + effect_variable_category_id Int @db.SmallInt + interesting_variable_category_pair Boolean + newest_data_at DateTime? @db.Timestamp(0) + analysis_requested_at DateTime? @db.Timestamp(0) + reason_for_analysis String @db.VarChar(255) + analysis_started_at DateTime? @db.Timestamp(0) + analysis_ended_at DateTime? @db.Timestamp(0) + user_error_message String? + internal_error_message String? + cause_variable_id Int + effect_variable_id Int + cause_baseline_average_per_day Float + cause_baseline_average_per_duration_of_action Float + cause_treatment_average_per_day Float + cause_treatment_average_per_duration_of_action Float + effect_baseline_average Float + effect_baseline_relative_standard_deviation Float + effect_baseline_standard_deviation Float + effect_follow_up_average Float + effect_follow_up_percent_change_from_baseline Float + z_score Float + charts Json @db.Json + number_of_variables_where_best_cohort_correlation Int + deletion_reason String? @db.VarChar(280) + record_size_in_kb Int? + is_public Boolean? + slug String? @unique(map: "cohort_study_statistics_slug_uindex") @db.VarChar(200) + boring Boolean? + outcome_is_a_goal Boolean? + predictor_is_controllable Boolean? + plausibly_causal Boolean? + obvious Boolean? + number_of_up_votes Int + number_of_down_votes Int + strength_level String @db.VarChar(255) + confidence_level String @db.VarChar(255) + relationship String @db.VarChar(255) + units units? @relation(fields: [cause_unit_id], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "cohort_study_statistics_cause_unit_id_fk") + variable_categories_cohort_study_statistics_cause_variable_category_idTovariable_categories variable_categories @relation("cohort_study_statistics_cause_variable_category_idTovariable_categories", fields: [cause_variable_category_id], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "cohort_study_statistics_cause_variable_category_id_fk") + variables_cohort_study_statistics_cause_variable_idTovariables global_variables @relation("cohort_study_statistics_cause_variable_idTovariables", fields: [cause_variable_id], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "cohort_study_statistics_cause_variables_id_fk") + oa_clients oa_clients? @relation(fields: [client_id], references: [client_id], onDelete: NoAction, onUpdate: NoAction, map: "cohort_study_statistics_client_id_fk") + variable_categories_cohort_study_statistics_effect_variable_category_idTovariable_categories variable_categories @relation("cohort_study_statistics_effect_variable_category_idTovariable_categories", fields: [effect_variable_category_id], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "cohort_study_statistics_effect_variable_category_id_fk") + variables_cohort_study_statistics_effect_variable_idTovariables global_variables @relation("cohort_study_statistics_effect_variable_idTovariables", fields: [effect_variable_id], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "cohort_study_statistics_effect_variables_id_fk") + + @@unique([cause_variable_id, effect_variable_id], map: "cs_cause_variable_id_effect_variable_id_uindex") + @@index([cause_unit_id], map: "cohort_study_statistics_cause_unit_id_fk") + @@index([cause_variable_category_id], map: "cohort_study_statistics_cause_variable_category_id_fk") + @@index([client_id], map: "cohort_study_statistics_client_id_fk") + @@index([effect_variable_category_id], map: "cohort_study_statistics_effect_variable_category_id_fk") + @@index([effect_variable_id], map: "cohort_study_statistics_effect_variable_id_index") +} + +model common_tags { + id Int @id @default(autoincrement()) + tagged_variable_id Int + tag_variable_id Int + number_of_data_points Int? + standard_error Float? + tag_variable_unit_id Int? @db.SmallInt + tagged_variable_unit_id Int? @db.SmallInt + conversion_factor Float + client_id String? @db.VarChar(80) + created_at DateTime @default(now()) @db.Timestamp(0) + updated_at DateTime @default(now()) @db.Timestamp(0) + deleted_at DateTime? @db.Timestamp(0) + oa_clients oa_clients? @relation(fields: [client_id], references: [client_id], onDelete: NoAction, onUpdate: NoAction, map: "common_tags_client_id_fk") + variables_common_tags_tag_variable_idTovariables global_variables @relation("common_tags_tag_variable_idTovariables", fields: [tag_variable_id], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "common_tags_tag_variable_id_variables_id_fk") + units_common_tags_tag_variable_unit_idTounits units? @relation("common_tags_tag_variable_unit_idTounits", fields: [tag_variable_unit_id], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "common_tags_tag_variable_unit_id_fk") + variables_common_tags_tagged_variable_idTovariables global_variables @relation("common_tags_tagged_variable_idTovariables", fields: [tagged_variable_id], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "common_tags_tagged_variable_id_variables_id_fk") + units_common_tags_tagged_variable_unit_idTounits units? @relation("common_tags_tagged_variable_unit_idTounits", fields: [tagged_variable_unit_id], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "common_tags_tagged_variable_unit_id_fk") + + @@unique([tagged_variable_id, tag_variable_id], map: "UK_tag_tagged") + @@index([client_id], map: "common_tags_client_id_fk") + @@index([tag_variable_id], map: "common_tags_tag_variable_id_variables_id_fk") + @@index([tag_variable_unit_id], map: "common_tags_tag_variable_unit_id_fk") + @@index([tagged_variable_unit_id], map: "common_tags_tagged_variable_unit_id_fk") +} + +model connections { + id Int @id @default(autoincrement()) + client_id String? @db.VarChar(80) + user_id BigInt + connector_id Int + connect_status String @db.VarChar(32) + connect_error String? + update_requested_at DateTime? @db.Timestamp(0) + update_status String @db.VarChar(32) + update_error String? + last_successful_updated_at DateTime? @db.Timestamp(0) + created_at DateTime @default(now()) @db.Timestamp(0) + updated_at DateTime @default(now()) @db.Timestamp(0) + deleted_at DateTime? @db.Timestamp(0) + total_measurements_in_last_update Int? + user_message String? @db.VarChar(255) + latest_measurement_at DateTime? @db.Timestamp(0) + import_started_at DateTime? @db.Timestamp(0) + import_ended_at DateTime? @db.Timestamp(0) + reason_for_import String? @db.VarChar(255) + user_error_message String? + internal_error_message String? + dfda_post_id BigInt? + number_of_connector_imports Int? + number_of_connector_requests Int? + credentials String? + imported_data_from_at DateTime? @db.Timestamp(0) + imported_data_end_at DateTime? @db.Timestamp(0) + number_of_measurements Int? + is_public Boolean? + slug String? @unique(map: "connections_slug_uindex") @db.VarChar(200) + meta String? + connector_user_id String? @db.VarChar(255) + connector_user_email String? @db.VarChar(255) + oa_clients oa_clients? @relation(fields: [client_id], references: [client_id], onDelete: NoAction, onUpdate: NoAction, map: "connections_client_id_fk") + connectors connectors @relation(fields: [connector_id], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "connections_connectors_id_fk") + dfda_users dfda_users @relation(fields: [user_id], references: [ID], onDelete: NoAction, onUpdate: NoAction, map: "connections_user_id_fk") + connector_imports connector_imports[] + connector_requests connector_requests[] + measurements measurements[] + + @@unique([user_id, connector_id], map: "UX_userId_connectorId") + @@index([connect_status], map: "IDX_status") + @@index([client_id], map: "connections_client_id_fk") + @@index([connector_id], map: "connections_connectors_id_fk") + @@index([dfda_post_id], map: "connections_dfda_posts_ID_fk") + @@index([connector_user_id, connector_id], map: "connector_user_id_uindex") + @@index([update_status], map: "status") + @@index([update_requested_at, update_status], map: "status_update_requested") +} + +model connector_imports { + id Int @id @default(autoincrement()) + client_id String? @db.VarChar(80) + connection_id Int? + connector_id Int + created_at DateTime @default(now()) @db.Timestamp(0) + deleted_at DateTime? @db.Timestamp(0) + earliest_measurement_at DateTime? @db.Timestamp(0) + import_ended_at DateTime? @db.Timestamp(0) + import_started_at DateTime? @db.Timestamp(0) + internal_error_message String? + latest_measurement_at DateTime? @db.Timestamp(0) + number_of_measurements Int @default(0) + reason_for_import String? @db.VarChar(255) + success Boolean? @default(true) + updated_at DateTime @default(now()) @db.Timestamp(0) + user_error_message String? + user_id BigInt + additional_meta_data Json? @db.Json + number_of_connector_requests Int? + imported_data_from_at DateTime? @db.Timestamp(0) + imported_data_end_at DateTime? @db.Timestamp(0) + credentials String? + oa_clients oa_clients? @relation(fields: [client_id], references: [client_id], onDelete: NoAction, onUpdate: NoAction, map: "connector_imports_client_id_fk") + connections connections? @relation(fields: [connection_id], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "connector_imports_connections_id_fk") + connectors connectors @relation(fields: [connector_id], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "connector_imports_connectors_id_fk") + dfda_users dfda_users @relation(fields: [user_id], references: [ID], onDelete: NoAction, onUpdate: NoAction, map: "connector_imports_dfda_users_ID_fk") + connector_requests connector_requests[] + measurements measurements[] + + @@unique([connection_id, created_at], map: "connector_imports_connection_id_created_at_uindex") + @@unique([connector_id, user_id, created_at], map: "connector_imports_connector_id_user_id_created_at_uindex") + @@index([user_id, connector_id], map: "IDX_connector_imports_user_connector") + @@index([client_id], map: "connector_imports_client_id_fk") +} + +model connector_requests { + id Int @id @default(autoincrement()) + connector_id Int + user_id BigInt + connection_id Int? + connector_import_id Int + method String @db.VarChar(10) + code Int + uri String @db.VarChar(2083) + response_body String? + request_body String? + request_headers String + created_at DateTime @default(now()) @db.Timestamp(0) + updated_at DateTime @default(now()) @db.Timestamp(0) + deleted_at DateTime? @db.Timestamp(0) + content_type String? @db.VarChar(100) + imported_data_from_at DateTime? @db.Timestamp(0) + connections connections? @relation(fields: [connection_id], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "connector_requests_connections_id_fk") + connector_imports connector_imports @relation(fields: [connector_import_id], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "connector_requests_connector_imports_id_fk") + connectors connectors @relation(fields: [connector_id], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "connector_requests_connectors_id_fk") + dfda_users dfda_users @relation(fields: [user_id], references: [ID], onDelete: NoAction, onUpdate: NoAction, map: "connector_requests_dfda_users_ID_fk") + + @@index([connection_id], map: "connector_requests_connections_id_fk") + @@index([connector_import_id], map: "connector_requests_connector_imports_id_fk") + @@index([connector_id], map: "connector_requests_connectors_id_fk") + @@index([user_id], map: "connector_requests_dfda_users_ID_fk") +} + +model connectors { + id Int @id @default(autoincrement()) + name String @unique(map: "connectors_name_unique") @db.VarChar(30) + display_name String @db.VarChar(30) + image String @db.VarChar(2083) + get_it_url String? @db.VarChar(2083) + short_description String + long_description String + enabled Boolean @default(true) + oauth Boolean @default(false) + qm_client Boolean? @default(false) + created_at DateTime @default(now()) @db.Timestamp(0) + updated_at DateTime @default(now()) @db.Timestamp(0) + client_id String? @db.VarChar(80) + deleted_at DateTime? @db.Timestamp(0) + dfda_post_id BigInt? + number_of_connections Int? + number_of_connector_imports Int? + number_of_connector_requests Int? + number_of_measurements Int? + is_public Boolean? + sort_order Int? + slug String? @unique(map: "connectors_slug_uindex") @db.VarChar(200) + available_outside_us Boolean @default(true) + connections connections[] + connector_imports connector_imports[] + connector_requests connector_requests[] + oa_clients oa_clients? @relation(fields: [client_id], references: [client_id], onDelete: NoAction, onUpdate: NoAction, map: "connectors_client_id_fk") + + measurements measurements[] + + @@index([client_id], map: "connectors_client_id_fk") + @@index([dfda_post_id], map: "connectors_dfda_posts_ID_fk") +} + +model correlation_causality_votes { + id Int @id @default(autoincrement()) + cause_variable_id Int + effect_variable_id Int + correlation_id Int? + aggregate_correlation_id Int? + user_id BigInt + vote Int + created_at DateTime @default(now()) @db.Timestamp(0) + updated_at DateTime @default(now()) @db.Timestamp(0) + deleted_at DateTime? @db.Timestamp(0) + client_id String? @db.VarChar(80) + is_public Boolean? + global_variable_relationships global_variable_relationships? @relation(fields: [aggregate_correlation_id], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "correlation_causality_votes_global_variable_relationships_id_fk") + variables_correlation_causality_votes_cause_variable_idTovariables global_variables @relation("correlation_causality_votes_cause_variable_idTovariables", fields: [cause_variable_id], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "correlation_causality_votes_cause_variables_id_fk") + oa_clients oa_clients? @relation(fields: [client_id], references: [client_id], onDelete: NoAction, onUpdate: NoAction, map: "correlation_causality_votes_client_id_fk") + user_variable_relationships user_variable_relationships? @relation(fields: [correlation_id], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "correlation_causality_votes_user_variable_relationships_id_fk") + variables_correlation_causality_votes_effect_variable_idTovariables global_variables @relation("correlation_causality_votes_effect_variable_idTovariables", fields: [effect_variable_id], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "correlation_causality_votes_effect_variables_id_fk") + dfda_users dfda_users @relation(fields: [user_id], references: [ID], onDelete: NoAction, onUpdate: NoAction, map: "correlation_causality_votes_dfda_users_ID_fk") + + @@unique([user_id, cause_variable_id, effect_variable_id], map: "correlation_causality_votes_user_cause_effect_uindex") + @@index([aggregate_correlation_id], map: "correlation_causality_votes_global_variable_relationships_id_fk") + @@index([cause_variable_id], map: "correlation_causality_votes_cause_variables_id_fk") + @@index([client_id], map: "correlation_causality_votes_client_id_fk") + @@index([correlation_id], map: "correlation_causality_votes_user_variable_relationships_id_fk") + @@index([effect_variable_id], map: "correlation_causality_votes_effect_variables_id_fk") +} + +model variable_relationship_usefulness_votes { + id Int @id @default(autoincrement()) + cause_variable_id Int + effect_variable_id Int + correlation_id Int? + aggregate_correlation_id Int? + user_id BigInt + vote Int + created_at DateTime @default(now()) @db.Timestamp(0) + updated_at DateTime @default(now()) @db.Timestamp(0) + deleted_at DateTime? @db.Timestamp(0) + client_id String? @db.VarChar(80) + is_public Boolean? + global_variable_relationships global_variable_relationships? @relation(fields: [aggregate_correlation_id], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "variable_relationship_usefulness_votes_global_variable_relationships_id_fk") + variables_variable_relationship_usefulness_votes_cause_variable_idTovariables global_variables @relation("variable_relationship_usefulness_votes_cause_variable_idTovariables", fields: [cause_variable_id], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "variable_relationship_usefulness_votes_cause_variables_id_fk") + oa_clients oa_clients? @relation(fields: [client_id], references: [client_id], onDelete: NoAction, onUpdate: NoAction, map: "variable_relationship_usefulness_votes_client_id_fk") + user_variable_relationships user_variable_relationships? @relation(fields: [correlation_id], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "variable_relationship_usefulness_votes_user_variable_relationships_id_fk") + variables_variable_relationship_usefulness_votes_effect_variable_idTovariables global_variables @relation("variable_relationship_usefulness_votes_effect_variable_idTovariables", fields: [effect_variable_id], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "variable_relationship_usefulness_votes_effect_variables_id_fk") + dfda_users dfda_users @relation(fields: [user_id], references: [ID], onDelete: NoAction, onUpdate: NoAction, map: "variable_relationship_usefulness_votes_dfda_users_ID_fk") + + @@unique([user_id, cause_variable_id, effect_variable_id], map: "variable_relationship_usefulness_votes_user_cause_effect_uindex") + @@index([aggregate_correlation_id], map: "variable_relationship_usefulness_votes_global_variable_relationships_id_fk") + @@index([cause_variable_id], map: "variable_relationship_usefulness_votes_cause_variables_id_fk") + @@index([client_id], map: "variable_relationship_usefulness_votes_client_id_fk") + @@index([correlation_id], map: "variable_relationship_usefulness_votes_user_variable_relationships_id_fk") + @@index([effect_variable_id], map: "variable_relationship_usefulness_votes_effect_variables_id_fk") +} + + + +model user_variable_relationships { + id Int @id @default(autoincrement()) + user_id BigInt + cause_variable_id Int + effect_variable_id Int + qm_score Float? + forward_pearson_correlation_coefficient Float? + value_predicting_high_outcome Float? + value_predicting_low_outcome Float? + predicts_high_effect_change Int? + predicts_low_effect_change Int + average_effect Float + average_effect_following_high_cause Float + average_effect_following_low_cause Float + average_daily_low_cause Float + average_daily_high_cause Float + average_forward_pearson_correlation_over_onset_delays Float? + average_reverse_pearson_correlation_over_onset_delays Float? + cause_changes Int + cause_filling_value Float? + cause_number_of_processed_daily_measurements Int + cause_number_of_raw_measurements Int + cause_unit_id Int? @db.SmallInt + confidence_interval Float + critical_t_value Float + created_at DateTime @default(now()) @db.Timestamp(0) + data_source_name String? @db.VarChar(255) + deleted_at DateTime? @db.Timestamp(0) + duration_of_action Int + effect_changes Int + effect_filling_value Float? + effect_number_of_processed_daily_measurements Int + effect_number_of_raw_measurements Int + forward_spearman_correlation_coefficient Float + number_of_days Int + number_of_pairs Int + onset_delay Int + onset_delay_with_strongest_pearson_correlation Int? + optimal_pearson_product Float? + p_value Float? + pearson_correlation_with_no_onset_delay Float? + predictive_pearson_correlation_coefficient Float? + reverse_pearson_correlation_coefficient Float? + statistical_significance Float? + strongest_pearson_correlation_coefficient Float? + t_value Float? + updated_at DateTime @default(now()) @db.Timestamp(0) + grouped_cause_value_closest_to_value_predicting_low_outcome Float + grouped_cause_value_closest_to_value_predicting_high_outcome Float + client_id String? @db.VarChar(255) + published_at DateTime? @db.Timestamp(0) + dfda_post_id BigInt? + status String? @db.VarChar(25) + cause_variable_category_id Int @db.SmallInt + effect_variable_category_id Int @db.SmallInt + interesting_variable_category_pair Boolean + newest_data_at DateTime? @db.Timestamp(0) + analysis_requested_at DateTime? @db.Timestamp(0) + reason_for_analysis String @db.VarChar(255) + analysis_started_at DateTime? @db.Timestamp(0) + analysis_ended_at DateTime? @db.Timestamp(0) + user_error_message String? + internal_error_message String? + cause_user_variable_id Int + effect_user_variable_id Int + latest_measurement_start_at DateTime? @db.Timestamp(0) + earliest_measurement_start_at DateTime? @db.Timestamp(0) + cause_baseline_average_per_day Float + cause_baseline_average_per_duration_of_action Float + cause_treatment_average_per_day Float + cause_treatment_average_per_duration_of_action Float + effect_baseline_average Float? + effect_baseline_relative_standard_deviation Float + effect_baseline_standard_deviation Float? + effect_follow_up_average Float + effect_follow_up_percent_change_from_baseline Float + z_score Float? + experiment_start_at DateTime? @db.Timestamp(0) + experiment_end_at DateTime? @db.Timestamp(0) + aggregate_correlation_id Int? + aggregated_at DateTime? @db.Timestamp(0) + usefulness_vote Int? + causality_vote Int? + deletion_reason String? @db.VarChar(280) + record_size_in_kb Int? + correlations_over_durations String? + correlations_over_delays String? + is_public Boolean? + sort_order Int? + slug String? @unique(map: "correlations_slug_uindex") @db.VarChar(200) + boring Boolean? + outcome_is_goal Boolean? + predictor_is_controllable Boolean? + plausibly_causal Boolean? + obvious Boolean? + number_of_up_votes Int? + number_of_down_votes Int? + strength_level String @db.VarChar(255) + confidence_level String @db.VarChar(255) + relationship String @db.VarChar(255) + correlation_causality_votes correlation_causality_votes[] + variable_relationship_usefulness_votes variable_relationship_usefulness_votes[] + global_variable_relationships global_variable_relationships? @relation(fields: [aggregate_correlation_id], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "user_variable_relationships_global_variable_relationships_id_fk") + units units? @relation(fields: [cause_unit_id], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "user_variable_relationships_cause_unit_id_fk") + variable_categories variable_categories @relation(fields: [cause_variable_category_id], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "user_variable_relationships_cause_variable_category_id_fk") + variables_user_variable_relationships_cause_variable_idTovariables global_variables @relation("user_variable_relationships_cause_variable_idTovariables", fields: [cause_variable_id], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "user_variable_relationships_cause_variable_id_fk") + oa_clients oa_clients? @relation(fields: [client_id], references: [client_id], onDelete: NoAction, onUpdate: NoAction, map: "user_variable_relationships_client_id_fk") + variables_user_variable_relationships_effect_variable_idTovariables global_variables @relation("user_variable_relationships_effect_variable_idTovariables", fields: [effect_variable_id], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "user_variable_relationships_effect_variable_id_fk") + dfda_users dfda_users @relation(fields: [user_id], references: [ID], onDelete: NoAction, onUpdate: NoAction, map: "user_variable_relationships_user_id_fk") + user_variables_user_variable_relationships_cause_user_variable_idTouser_variables user_variables @relation("user_variable_relationships_cause_user_variable_idTouser_variables", fields: [cause_user_variable_id], references: [id], onDelete: Cascade, map: "user_variable_relationships_user_variables_cause_user_variable_id_fk") + user_variables_user_variable_relationships_effect_user_variable_idTouser_variables user_variables @relation("user_variable_relationships_effect_user_variable_idTouser_variables", fields: [effect_user_variable_id], references: [id], onDelete: Cascade, map: "user_variable_relationships_user_variables_effect_user_variable_id_fk") + user_studies user_studies? + user_variables_user_variables_best_user_correlation_idTouser_variable_relationships user_variables[] @relation("user_variables_best_user_correlation_idTouser_variable_relationships") + votes votes[] + + @@unique([user_id, cause_variable_id, effect_variable_id], map: "user_variable_relationships_pk") + @@unique([user_id, cause_variable_id, effect_variable_id], map: "user_variable_relationships_user_id_cause_variable_id_effect_variable_id_uinde") + @@index([effect_variable_category_id], map: "c_effect_variable_category_id_fk") + @@index([aggregate_correlation_id], map: "user_variable_relationships_global_variable_relationships_id_fk") + @@index([analysis_started_at], map: "user_variable_relationships_analysis_started_at_index") + @@index([cause_unit_id], map: "user_variable_relationships_cause_unit_id_fk") + @@index([cause_variable_category_id], map: "user_variable_relationships_cause_variable_category_id_fk") + @@index([cause_variable_id], map: "user_variable_relationships_cause_variable_id_fk") + @@index([client_id], map: "user_variable_relationships_client_id_fk") + @@index([deleted_at, analysis_ended_at], map: "user_variable_relationships_deleted_at_analysis_ended_at_index") + @@index([effect_variable_id], map: "user_variable_relationships_effect_variable_id_fk") + @@index([updated_at], map: "user_variable_relationships_updated_at_index") + @@index([user_id, deleted_at, qm_score], map: "user_variable_relationships_user_id_deleted_at_qm_score_index") + @@index([cause_user_variable_id], map: "user_variable_relationships_user_variables_cause_user_variable_id_fk") + @@index([effect_user_variable_id], map: "user_variable_relationships_user_variables_effect_user_variable_id_fk") + @@index([dfda_post_id], map: "user_variable_relationships_dfda_posts_ID_fk") + @@index([user_id, cause_variable_id, deleted_at, qm_score], map: "user_id_cause_variable_id_deleted_at_qm_score_index") + @@index([user_id, effect_variable_id, deleted_at, qm_score], map: "user_id_effect_variable_id_deleted_at_qm_score_index") +} + +model device_tokens { + device_token String @id @db.VarChar(255) + created_at DateTime @default(now()) @db.Timestamp(0) + updated_at DateTime @default(now()) @db.Timestamp(0) + deleted_at DateTime? @db.Timestamp(0) + user_id BigInt + number_of_waiting_tracking_reminder_notifications Int? + last_notified_at DateTime? @db.Timestamp(0) + platform String @db.VarChar(255) + number_of_new_tracking_reminder_notifications Int? + number_of_notifications_last_sent Int? + error_message String? @db.VarChar(255) + last_checked_at DateTime? @db.Timestamp(0) + received_at DateTime? @db.Timestamp(0) + server_ip String? @db.VarChar(255) + server_hostname String? @db.VarChar(255) + client_id String? @db.VarChar(255) + oa_clients oa_clients? @relation(fields: [client_id], references: [client_id], onDelete: NoAction, onUpdate: NoAction, map: "device_tokens_client_id_fk") + dfda_users dfda_users @relation(fields: [user_id], references: [ID], onDelete: NoAction, onUpdate: NoAction, map: "device_tokens_user_id_fk") + + @@index([client_id], map: "device_tokens_client_id_fk") + @@index([user_id], map: "index_user_id") +} + +model global_studies { + id Int @id + aggregate_correlation_id Int? + cause_variable_id Int + effect_variable_id Int + cause_user_variable_id Int + effect_user_variable_id Int + user_id BigInt + created_at DateTime @default(now()) @db.Timestamp(0) + deleted_at DateTime? @db.Timestamp(0) + analysis_parameters String? + user_study_text String? + user_title String? + study_status String @default("publish") @db.VarChar(20) + comment_status String @default("open") @db.VarChar(20) + study_password String? @db.VarChar(20) + study_images String? + updated_at DateTime @default(now()) @db.Timestamp(0) + client_id String? @db.VarChar(255) + published_at DateTime? @db.Timestamp(0) + dfda_post_id Int? + newest_data_at DateTime? @db.Timestamp(0) + analysis_requested_at DateTime? @db.Timestamp(0) + reason_for_analysis String? @db.VarChar(255) + analysis_ended_at DateTime? @db.Timestamp(0) + analysis_started_at DateTime? @db.Timestamp(0) + internal_error_message String? @db.VarChar(255) + user_error_message String? @db.VarChar(255) + status String? @db.VarChar(25) + analysis_settings_modified_at DateTime? @db.Timestamp(0) + is_public Boolean + sort_order Int? + slug String? @unique(map: "global_studies_slug_uindex") @db.VarChar(200) + global_variable_relationships global_variable_relationships? @relation(fields: [aggregate_correlation_id], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "global_studies_global_variable_relationships_id_fk") + variables_global_studies_cause_variable_idTovariables global_variables @relation("global_studies_cause_variable_idTovariables", fields: [cause_variable_id], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "global_studies_cause_variable_id_variables_id_fk") + oa_clients oa_clients? @relation(fields: [client_id], references: [client_id], onDelete: NoAction, onUpdate: NoAction, map: "global_studies_client_id_fk") + variables_global_studies_effect_variable_idTovariables global_variables @relation("global_studies_effect_variable_idTovariables", fields: [effect_variable_id], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "global_studies_effect_variable_id_variables_id_fk") + dfda_users dfda_users @relation(fields: [user_id], references: [ID], onDelete: NoAction, onUpdate: NoAction, map: "global_studies_user_id_fk") + + @@unique([user_id, cause_variable_id, effect_variable_id], map: "global_studies_cause_effect") + @@index([aggregate_correlation_id], map: "global_studies_global_variable_relationships_id_fk") + @@index([cause_variable_id], map: "global_studies_cause_variable_id") + @@index([client_id], map: "global_studies_client_id_fk") + @@index([effect_variable_id], map: "global_studies_effect_variable_id") +} + + + +model measurement_exports { + id Int @id @default(autoincrement()) + user_id BigInt + client_id String? @db.VarChar(255) + status String @db.VarChar(32) + type String @default("user") @db.VarChar(255) + output_type String @default("csv") @db.VarChar(255) + error_message String? @db.VarChar(255) + created_at DateTime @default(now()) @db.Timestamp(0) + updated_at DateTime @default(now()) @db.Timestamp(0) + deleted_at DateTime? @db.Timestamp(0) + oa_clients oa_clients? @relation(fields: [client_id], references: [client_id], onDelete: NoAction, onUpdate: NoAction, map: "measurement_exports_client_id_fk") + dfda_users dfda_users @relation(fields: [user_id], references: [ID], onDelete: NoAction, onUpdate: NoAction, map: "measurement_exports_user_id_fk") + + @@index([client_id], map: "measurement_exports_client_id_fk") + @@index([user_id], map: "measurement_exports_user_id_fk") +} + +model measurement_imports { + id Int @id @default(autoincrement()) + user_id BigInt + file String @db.VarChar(255) + created_at DateTime @default(now()) @db.Timestamp(0) + updated_at DateTime @default(now()) @db.Timestamp(0) + status String @default("WAITING") @db.VarChar(25) + error_message String? + source_name String? @db.VarChar(80) + deleted_at DateTime? @db.Timestamp(0) + client_id String? @db.VarChar(255) + import_started_at DateTime? @db.Timestamp(0) + import_ended_at DateTime? @db.Timestamp(0) + reason_for_import String? @db.VarChar(255) + user_error_message String? @db.VarChar(255) + internal_error_message String? @db.VarChar(255) + oa_clients oa_clients? @relation(fields: [client_id], references: [client_id], onDelete: NoAction, onUpdate: NoAction, map: "measurement_imports_client_id_fk") + dfda_users dfda_users @relation(fields: [user_id], references: [ID], onDelete: NoAction, onUpdate: NoAction, map: "measurement_imports_user_id_fk") + + @@index([client_id], map: "measurement_imports_client_id_fk") + @@index([user_id], map: "measurement_imports_user_id_fk") +} + +model measurements { + id BigInt @id @default(autoincrement()) + user_id BigInt + client_id String? @db.VarChar(80) + connector_id Int? + variable_id Int + start_time Int + value Float + unit_id Int @db.SmallInt + original_value Float + original_unit_id Int @db.SmallInt + duration Int? + note String? + latitude Float? + longitude Float? + location String? @db.VarChar(255) + created_at DateTime @default(now()) @db.Timestamp(0) + updated_at DateTime @default(now()) @db.Timestamp(0) + error String? + variable_category_id Int @db.SmallInt + deleted_at DateTime? @db.Timestamp(0) + source_name String? @db.VarChar(80) + user_variable_id Int + start_at DateTime? @db.Timestamp(0) + connection_id Int? + connector_import_id Int? + deletion_reason String? @db.VarChar(280) + original_start_at DateTime? @db.Timestamp(0) + oa_clients oa_clients? @relation(fields: [client_id], references: [client_id], onDelete: NoAction, onUpdate: NoAction, map: "measurements_client_id_fk") + connections connections? @relation(fields: [connection_id], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "measurements_connections_id_fk") + connector_imports connector_imports? @relation(fields: [connector_import_id], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "measurements_connector_imports_id_fk") + connectors connectors? @relation(fields: [connector_id], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "measurements_connectors_id_fk") + units_measurements_original_unit_idTounits units @relation("measurements_original_unit_idTounits", fields: [original_unit_id], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "measurements_original_unit_id_fk") + units_measurements_unit_idTounits units @relation("measurements_unit_idTounits", fields: [unit_id], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "measurements_unit_id_fk") + dfda_users dfda_users @relation(fields: [user_id], references: [ID], onDelete: NoAction, onUpdate: NoAction, map: "measurements_user_id_fk") + user_variables user_variables @relation(fields: [user_variable_id], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "measurements_user_variables_user_variable_id_fk") + variable_categories variable_categories @relation(fields: [variable_category_id], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "measurements_variable_category_id_fk") + variables global_variables @relation(fields: [variable_id], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "measurements_variables_id_fk") + + @@unique([user_id, variable_id, start_time], map: "measurements_pk") + @@index([unit_id], map: "fk_measurementUnits") + @@index([client_id], map: "measurements_client_id_fk") + @@index([connection_id], map: "measurements_connections_id_fk") + @@index([connector_import_id], map: "measurements_connector_imports_id_fk") + @@index([connector_id], map: "measurements_connectors_id_fk") + @@index([original_unit_id], map: "measurements_original_unit_id_fk") + @@index([start_time], map: "measurements_start_time_index") + @@index([user_id, variable_category_id, start_time], map: "measurements_user_id_variable_category_id_start_time_index") + @@index([user_variable_id], map: "measurements_user_variables_user_variable_id_fk") + @@index([variable_id, user_id], map: "measurements_user_variables_variable_id_user_id_fk") + @@index([variable_category_id], map: "measurements_variable_category_id_fk") + @@index([variable_id, start_time], map: "measurements_variable_id_start_time_index") + @@index([variable_id, value, start_time], map: "measurements_variable_id_value_start_time_index") +} + +model patient_physicians { + id Int @id @default(autoincrement()) + patient_user_id BigInt + physician_user_id BigInt + scopes String @db.VarChar(2000) + created_at DateTime @default(now()) @db.Timestamp(0) + updated_at DateTime @default(now()) @db.Timestamp(0) + deleted_at DateTime? @db.Timestamp(0) + dfda_users_patient_physicians_patient_user_idTodfda_users dfda_users @relation("patient_physicians_patient_user_idTodfda_users", fields: [patient_user_id], references: [ID], onDelete: NoAction, onUpdate: NoAction, map: "patient_physicians_dfda_users_ID_fk") + dfda_users_patient_physicians_physician_user_idTodfda_users dfda_users @relation("patient_physicians_physician_user_idTodfda_users", fields: [physician_user_id], references: [ID], onDelete: NoAction, onUpdate: NoAction, map: "patient_physicians_dfda_users_ID_fk_2") + + @@unique([patient_user_id, physician_user_id], map: "patients_patient_user_id_physician_user_id_uindex") + @@index([physician_user_id], map: "patient_physicians_dfda_users_ID_fk_2") +} + +/// This model has constraints using non-default deferring rules and requires additional setup for migrations. Visit https://pris.ly/d/constraint-deferring for more info. +model phrases { + client_id String @db.VarChar(80) + created_at DateTime @default(now()) @db.Timestamp(0) + deleted_at DateTime? @db.Timestamp(0) + id Int @id @default(autoincrement()) + image String? @db.VarChar(100) + text String + title String? @db.VarChar(80) + type String @db.VarChar(80) + updated_at DateTime @default(now()) @db.Timestamp(0) + url String? @db.VarChar(100) + user_id BigInt + responding_to_phrase_id Int? + response_phrase_id Int? + recipient_user_ids String? + number_of_times_heard Int? + interpretative_confidence Float? + oa_clients oa_clients @relation(fields: [client_id], references: [client_id], onDelete: NoAction, onUpdate: NoAction, map: "phrases_client_id_fk") + dfda_users dfda_users @relation(fields: [user_id], references: [ID], onDelete: NoAction, onUpdate: NoAction, map: "phrases_user_id_fk") + + @@index([client_id], map: "phrases_client_id_fk") +} + +model sent_emails { + id Int @id @default(autoincrement()) + user_id BigInt? + type String @db.VarChar(100) + created_at DateTime @default(now()) @db.Timestamp(0) + updated_at DateTime @default(now()) @db.Timestamp(0) + deleted_at DateTime? @db.Timestamp(0) + client_id String? @db.VarChar(255) + slug String? @db.VarChar(100) + response String? @db.VarChar(140) + content String? + dfda_post_id BigInt? + email_address String? @db.VarChar(255) + subject String @db.VarChar(255) + oa_clients oa_clients? @relation(fields: [client_id], references: [client_id], onDelete: NoAction, onUpdate: NoAction, map: "sent_emails_client_id_fk") + dfda_users dfda_users? @relation(fields: [user_id], references: [ID], onDelete: NoAction, onUpdate: NoAction, map: "sent_emails_user_id_fk") + + @@index([client_id], map: "sent_emails_client_id_fk") + @@index([user_id, type], map: "sent_emails_user_id_type_index") + @@index([dfda_post_id], map: "sent_emails_dfda_posts_ID_fk") +} + + + +model sharer_trustees { + id Int @id @default(autoincrement()) + sharer_user_id BigInt + trustee_user_id BigInt + scopes String @db.VarChar(2000) + relationship_type String @db.VarChar(255) + created_at DateTime @default(now()) @db.Timestamp(0) + updated_at DateTime @default(now()) @db.Timestamp(0) + deleted_at DateTime? @db.Timestamp(0) + dfda_users_sharer_trustees_sharer_user_idTodfda_users dfda_users @relation("sharer_trustees_sharer_user_idTodfda_users", fields: [sharer_user_id], references: [ID], onDelete: NoAction, onUpdate: NoAction, map: "sharer_trustees_dfda_users_ID_fk") + dfda_users_sharer_trustees_trustee_user_idTodfda_users dfda_users @relation("sharer_trustees_trustee_user_idTodfda_users", fields: [trustee_user_id], references: [ID], onDelete: NoAction, onUpdate: NoAction, map: "sharer_trustees_dfda_users_ID_fk_2") + + @@unique([sharer_user_id, trustee_user_id], map: "sharer_user_id_trustee_user_id_uindex") + @@index([trustee_user_id], map: "sharer_trustees_dfda_users_ID_fk_2") +} + +model spreadsheet_importers { + id Int @id @default(autoincrement()) + name String @db.VarChar(30) + display_name String @db.VarChar(30) + image String @db.VarChar(2083) + get_it_url String? @db.VarChar(2083) + short_description String + long_description String + enabled Boolean @default(true) + created_at DateTime @default(now()) @db.Timestamp(0) + updated_at DateTime @default(now()) @db.Timestamp(0) + client_id String? @db.VarChar(80) + deleted_at DateTime? @db.Timestamp(0) + dfda_post_id BigInt? + number_of_measurement_imports Int? + number_of_measurements Int? + sort_order Int? + oa_clients oa_clients? @relation(fields: [client_id], references: [client_id], onDelete: NoAction, onUpdate: NoAction, map: "spreadsheet_importers_client_id_fk") + + @@index([client_id], map: "spreadsheet_importers_client_id_fk") + @@index([dfda_post_id], map: "spreadsheet_importers_dfda_posts_ID_fk") +} + +model tracking_reminder_notifications { + id Int @id @default(autoincrement()) + tracking_reminder_id Int + created_at DateTime @default(now()) @db.Timestamp(0) + updated_at DateTime @default(now()) @db.Timestamp(0) + deleted_at DateTime? @db.Timestamp(0) + user_id BigInt + notified_at DateTime? @db.Timestamp(0) + received_at DateTime? @db.Timestamp(0) + client_id String? @db.VarChar(255) + variable_id Int + notify_at DateTime? @db.Timestamp(0) + user_variable_id Int + oa_clients oa_clients? @relation(fields: [client_id], references: [client_id], onDelete: NoAction, onUpdate: NoAction, map: "tracking_reminder_notifications_client_id_fk") + tracking_reminders tracking_reminders @relation(fields: [tracking_reminder_id], references: [id], onDelete: Cascade, map: "tracking_reminder_notifications_tracking_reminders_id_fk") + dfda_users dfda_users @relation(fields: [user_id], references: [ID], onDelete: Cascade, onUpdate: NoAction, map: "tracking_reminder_notifications_user_id_fk") + user_variables user_variables @relation(fields: [user_variable_id], references: [id], onDelete: Cascade, map: "tracking_reminder_notifications_user_variables_id_fk") + variables global_variables @relation(fields: [variable_id], references: [id], onDelete: Cascade, map: "tracking_reminder_notifications_variables_id_fk") + + @@unique([notify_at, tracking_reminder_id], map: "notify_at_tracking_reminder_id_uindex") + @@index([client_id], map: "tracking_reminder_notifications_client_id_fk") + @@index([tracking_reminder_id], map: "tracking_reminder_notifications_tracking_reminders_id_fk") + @@index([user_id], map: "tracking_reminder_notifications_user_id_fk") + @@index([user_variable_id], map: "tracking_reminder_notifications_user_variables_id_fk") + @@index([variable_id], map: "tracking_reminder_notifications_variable_id_fk") +} + +model tracking_reminders { + id Int @id @default(autoincrement()) + user_id BigInt + client_id String @db.VarChar(80) + variable_id Int + default_value Float? + reminder_start_time DateTime @default(dbgenerated("'00:00:00'::time without time zone")) @db.Time(0) + reminder_end_time DateTime? @db.Time(0) + reminder_sound String? @db.VarChar(125) + reminder_frequency Int? + pop_up Boolean? + sms Boolean? + email Boolean? + notification_bar Boolean? + last_tracked DateTime? @db.Timestamp(0) + created_at DateTime @default(now()) @db.Timestamp(0) + updated_at DateTime @default(now()) @db.Timestamp(0) + start_tracking_date DateTime? @db.Date + stop_tracking_date DateTime? @db.Date + instructions String? + deleted_at DateTime? @db.Timestamp(0) + image_url String? @db.VarChar(2083) + user_variable_id Int + latest_tracking_reminder_notification_notify_at DateTime? @db.Timestamp(0) + number_of_tracking_reminder_notifications Int? + tracking_reminder_notifications tracking_reminder_notifications[] + oa_clients oa_clients @relation(fields: [client_id], references: [client_id], onDelete: NoAction, onUpdate: NoAction, map: "tracking_reminders_client_id_fk") + dfda_users dfda_users @relation(fields: [user_id], references: [ID], onDelete: Cascade, map: "tracking_reminders_user_id_fk") + user_variables_tracking_reminders_user_id_variable_idTouser_variables user_variables @relation("tracking_reminders_user_id_variable_idTouser_variables", fields: [user_id, variable_id], references: [user_id, variable_id], onDelete: NoAction, onUpdate: NoAction, map: "tracking_reminders_user_variables_user_id_variable_id_fk") + user_variables_tracking_reminders_user_variable_idTouser_variables user_variables @relation("tracking_reminders_user_variable_idTouser_variables", fields: [user_variable_id], references: [id], onDelete: Cascade, map: "tracking_reminders_user_variables_user_variable_id_fk") + variables global_variables @relation(fields: [variable_id], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "tracking_reminders_variables_id_fk") + + @@unique([user_id, variable_id, reminder_start_time, reminder_frequency], map: "UK_user_var_time_freq") + @@index([client_id], map: "tracking_reminders_client_id_fk") + @@index([user_variable_id], map: "tracking_reminders_user_variables_user_variable_id_fk") + @@index([variable_id, user_id], map: "tracking_reminders_user_variables_variable_id_user_id_fk") + @@index([user_id, client_id], map: "user_client") +} + +/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments +model unit_categories { + id Int @id @default(autoincrement()) @db.SmallInt + name String @unique(map: "unit_categories_name_UNIQUE") @db.VarChar(64) + created_at DateTime @default(now()) @db.Timestamp(0) + updated_at DateTime @default(now()) @db.Timestamp(0) + can_be_summed Boolean @default(true) + deleted_at DateTime? @db.Timestamp(0) + sort_order Int? +} + + +/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments +model units { + id Int @id @default(autoincrement()) @db.SmallInt + name String @unique(map: "units_name_UNIQUE") @db.VarChar(64) + abbreviated_name String? @unique(map: "abbr_name_UNIQUE") @db.VarChar(40) + unit_category_id Int @db.SmallInt + minimum_value Float? + maximum_value Float? + created_at DateTime @default(now()) @db.Timestamp(0) + updated_at DateTime @default(now()) @db.Timestamp(0) + deleted_at DateTime? @db.Timestamp(0) + filling_type String @db.VarChar(255) + number_of_outcome_population_studies Int? + number_of_common_tags_where_tag_variable_unit Int? + number_of_common_tags_where_tagged_variable_unit Int? + number_of_outcome_case_studies Int? + number_of_measurements Int? + number_of_user_variables_where_default_unit Int? + number_of_variable_categories_where_default_unit Int? + number_of_variables_where_default_unit Int? + advanced Boolean + manual_tracking Boolean + filling_value Float? + scale String @db.VarChar(255) + conversion_steps String? + maximum_daily_value Float? + sort_order Int? + slug String? @unique(map: "units_slug_uindex") @db.VarChar(200) + code String? @db.VarChar(255) + descriptive_name String? @db.VarChar(255) + code_system String? @db.VarChar(255) + definition String? @db.VarChar(255) + synonym String? @db.VarChar(255) + status String? @db.VarChar(255) + kind_of_quantity String? @db.VarChar(255) + concept_id String? @db.VarChar(255) + dimension String? @db.VarChar(255) + global_variable_relationships global_variable_relationships[] + cohort_study_statistics cohort_study_statistics[] + common_tags_common_tags_tag_variable_unit_idTounits common_tags[] @relation("common_tags_tag_variable_unit_idTounits") + common_tags_common_tags_tagged_variable_unit_idTounits common_tags[] @relation("common_tags_tagged_variable_unit_idTounits") + user_variable_relationships user_variable_relationships[] + measurements_measurements_original_unit_idTounits measurements[] @relation("measurements_original_unit_idTounits") + measurements_measurements_unit_idTounits measurements[] @relation("measurements_unit_idTounits") + user_variables_user_variables_default_unit_idTounits user_variables[] @relation("user_variables_default_unit_idTounits") + user_variables_user_variables_last_unit_idTounits user_variables[] @relation("user_variables_last_unit_idTounits") + variable_categories variable_categories[] + variables global_variables[] + + @@index([unit_category_id], map: "fk_unitCategory") +} + +model user_studies { + id String @id @db.VarChar(80) + cause_variable_id Int + effect_variable_id Int + cause_user_variable_id Int + effect_user_variable_id Int + correlation_id Int? @unique(map: "user_studies_correlation_id_uindex") + user_id BigInt + created_at DateTime @default(now()) @db.Timestamp(0) + deleted_at DateTime? @db.Timestamp(0) + analysis_parameters String? + user_study_text String? + user_title String? + study_status String @default("publish") @db.VarChar(20) + comment_status String @default("open") @db.VarChar(20) + study_password String? @db.VarChar(20) + study_images String? + updated_at DateTime @default(now()) @db.Timestamp(0) + client_id String? @db.VarChar(255) + published_at DateTime? @db.Timestamp(0) + dfda_post_id Int? + newest_data_at DateTime? @db.Timestamp(0) + analysis_requested_at DateTime? @db.Timestamp(0) + reason_for_analysis String? @db.VarChar(255) + analysis_ended_at DateTime? @db.Timestamp(0) + analysis_started_at DateTime? @db.Timestamp(0) + internal_error_message String? @db.VarChar(255) + user_error_message String? @db.VarChar(255) + status String? @db.VarChar(25) + analysis_settings_modified_at DateTime? @db.Timestamp(0) + is_public Boolean? + sort_order Int? + slug String? @unique(map: "user_studies_slug_uindex") @db.VarChar(200) + user_variables_user_studies_cause_user_variable_idTouser_variables user_variables @relation("user_studies_cause_user_variable_idTouser_variables", fields: [cause_user_variable_id], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "user_studies_cause_user_variables_id_fk") + variables_user_studies_cause_variable_idTovariables global_variables @relation("user_studies_cause_variable_idTovariables", fields: [cause_variable_id], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "user_studies_cause_variables_id_fk") + user_variable_relationships user_variable_relationships? @relation(fields: [correlation_id], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "user_studies_user_variable_relationships_id_fk") + user_variables_user_studies_effect_user_variable_idTouser_variables user_variables @relation("user_studies_effect_user_variable_idTouser_variables", fields: [effect_user_variable_id], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "user_studies_effect_user_variables_id_fk") + variables_user_studies_effect_variable_idTovariables global_variables @relation("user_studies_effect_variable_idTovariables", fields: [effect_variable_id], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "user_studies_effect_variables_id_fk") + dfda_users dfda_users @relation(fields: [user_id], references: [ID], onDelete: NoAction, onUpdate: NoAction, map: "user_studies_user_id_fk") + + @@unique([user_id, cause_variable_id, effect_variable_id], map: "user_studies_user_cause_effect") + @@index([cause_user_variable_id], map: "user_studies_cause_user_variables_id_fk") + @@index([cause_variable_id], map: "user_studies_cause_variables_id_fk") + @@index([effect_user_variable_id], map: "user_studies_effect_user_variables_id_fk") + @@index([effect_variable_id], map: "user_studies_effect_variables_id_fk") +} + +model user_tags { + id Int @id @default(autoincrement()) + tagged_variable_id Int + tag_variable_id Int + conversion_factor Float + user_id BigInt + created_at DateTime @default(now()) @db.Timestamp(0) + updated_at DateTime @default(now()) @db.Timestamp(0) + client_id String? @db.VarChar(80) + deleted_at DateTime? @db.Timestamp(0) + tagged_user_variable_id Int? + tag_user_variable_id Int + oa_clients oa_clients? @relation(fields: [client_id], references: [client_id], onDelete: NoAction, onUpdate: NoAction, map: "user_tags_client_id_fk") + user_variables_user_tags_tag_user_variable_idTouser_variables user_variables @relation("user_tags_tag_user_variable_idTouser_variables", fields: [tag_user_variable_id], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "user_tags_tag_user_variable_id_fk") + user_variables_user_tags_tagged_user_variable_idTouser_variables user_variables? @relation("user_tags_tagged_user_variable_idTouser_variables", fields: [tagged_user_variable_id], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "user_tags_tagged_user_variable_id_fk") + variables global_variables @relation(fields: [tagged_variable_id], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "user_tags_tagged_variable_id_variables_id_fk") + dfda_users dfda_users @relation(fields: [user_id], references: [ID], onDelete: NoAction, onUpdate: NoAction, map: "user_tags_user_id_fk") + + @@unique([tagged_variable_id, tag_variable_id, user_id], map: "UK_user_tag_tagged") + @@index([tag_variable_id], map: "fk_conversionUnit") + @@index([client_id], map: "user_tags_client_id_fk") + @@index([tagged_user_variable_id], map: "user_tags_tagged_user_variable_id_fk") + @@index([user_id], map: "user_tags_user_id_fk") +} + +model user_variable_clients { + id Int @id @default(autoincrement()) + client_id String @db.VarChar(80) + created_at DateTime @default(now()) @db.Timestamp(0) + deleted_at DateTime? @db.Timestamp(0) + earliest_measurement_at DateTime? @db.Timestamp(0) + latest_measurement_at DateTime? @db.Timestamp(0) + number_of_measurements Int? + updated_at DateTime @default(now()) @db.Timestamp(0) + user_id BigInt + user_variable_id Int + variable_id Int + oa_clients oa_clients @relation(fields: [client_id], references: [client_id], onDelete: NoAction, onUpdate: NoAction, map: "user_variable_clients_client_id_fk") + dfda_users dfda_users @relation(fields: [user_id], references: [ID], onDelete: NoAction, onUpdate: NoAction, map: "user_variable_clients_user_id_fk") + user_variables user_variables @relation(fields: [user_variable_id], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "user_variable_clients_user_variables_user_variable_id_fk") + variables global_variables @relation(fields: [variable_id], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "user_variable_clients_variable_id_fk") + + @@unique([user_id, variable_id, client_id], map: "user_variable_clients_user") + @@index([client_id], map: "user_variable_clients_client_id_fk") + @@index([user_variable_id], map: "user_variable_clients_user_variables_user_variable_id_fk") + @@index([variable_id], map: "user_variable_clients_variable_id_fk") +} + +/// This model has constraints using non-default deferring rules and requires additional setup for migrations. Visit https://pris.ly/d/constraint-deferring for more info. +model user_variable_outcome_category { + id Int @id @default(autoincrement()) + user_variable_id Int + variable_id Int + variable_category_id Int @db.SmallInt + number_of_outcome_user_variables Int + created_at DateTime @default(now()) @db.Timestamp(0) + updated_at DateTime @default(now()) @db.Timestamp(0) + deleted_at DateTime? @db.Timestamp(0) + user_variables user_variables @relation(fields: [user_variable_id], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "user_variable_outcome_category_user_variables_id_fk") + variable_categories variable_categories @relation(fields: [variable_category_id], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "user_variable_outcome_category_variable_categories_id_fk") + variables global_variables @relation(fields: [variable_id], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "user_variable_outcome_category_variables_id_fk") + + @@unique([user_variable_id, variable_category_id], map: "user_variable_outcome_category_uindex") + @@index([variable_category_id], map: "user_variable_outcome_category_variable_categories_id_fk") + @@index([variable_id], map: "user_variable_outcome_category_variables_id_fk") +} + +/// This model has constraints using non-default deferring rules and requires additional setup for migrations. Visit https://pris.ly/d/constraint-deferring for more info. +model user_variable_predictor_category { + id Int @id @default(autoincrement()) + user_variable_id Int + variable_id Int + variable_category_id Int @db.SmallInt + number_of_predictor_user_variables Int + created_at DateTime @default(now()) @db.Timestamp(0) + updated_at DateTime @default(now()) @db.Timestamp(0) + deleted_at DateTime? @db.Timestamp(0) + user_variables user_variables @relation(fields: [user_variable_id], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "user_variable_predictor_category_user_variables_id_fk") + variable_categories variable_categories @relation(fields: [variable_category_id], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "user_variable_predictor_category_variable_categories_id_fk") + variables global_variables @relation(fields: [variable_id], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "user_variable_predictor_category_variables_id_fk") + + @@unique([user_variable_id, variable_category_id], map: "user_variable_predictor_category_uindex") + @@index([variable_category_id], map: "user_variable_predictor_category_variable_categories_id_fk") + @@index([variable_id], map: "user_variable_predictor_category_variables_id_fk") +} + + + +model user_variables { + id Int @id @default(autoincrement()) + parent_id Int? + client_id String? @db.VarChar(80) + user_id BigInt + variable_id Int + default_unit_id Int? @db.SmallInt + minimum_allowed_value Float? + maximum_allowed_value Float? + filling_value Float? @default(-1) + join_with Int? + onset_delay Int? + duration_of_action Int? + variable_category_id Int? @db.SmallInt + cause_only Boolean? + filling_type String? @db.VarChar(255) + number_of_processed_daily_measurements Int? + measurements_at_last_analysis Int @default(0) + last_unit_id Int? @db.SmallInt + last_original_unit_id Int? @db.SmallInt + last_value Float? + last_original_value Float? + number_of_user_variable_relationships Int? + status String? @db.VarChar(25) + standard_deviation Float? + variance Float? + minimum_recorded_value Float? + maximum_recorded_value Float? + mean Float? + median Float? + most_common_original_unit_id Int? + most_common_value Float? + number_of_unique_daily_values Int? + number_of_unique_values Int? + number_of_changes Int? + skewness Float? + kurtosis Float? + latitude Float? + longitude Float? + location String? @db.VarChar(255) + created_at DateTime @default(now()) @db.Timestamp(0) + updated_at DateTime @default(now()) @db.Timestamp(0) + outcome Boolean? + data_sources_count String? + earliest_filling_time Int? + latest_filling_time Int? + last_processed_daily_value Float? + outcome_of_interest Boolean? @default(false) + predictor_of_interest Boolean? @default(false) + experiment_start_time DateTime? @db.Timestamp(0) + experiment_end_time DateTime? @db.Timestamp(0) + description String? + deleted_at DateTime? @db.Timestamp(0) + alias String? @db.VarChar(125) + second_to_last_value Float? + third_to_last_value Float? + number_of_user_user_variable_relationships_as_effect Int? + number_of_user_user_variable_relationships_as_cause Int? + combination_operation String? @db.VarChar(255) + informational_url String? @db.VarChar(2000) + most_common_connector_id Int? + valence String? @db.VarChar(255) + wikipedia_title String? @db.VarChar(100) + number_of_tracking_reminders Int + number_of_raw_measurements_with_tags_joins_children Int? + most_common_source_name String? @db.VarChar(255) + optimal_value_message String? @db.VarChar(500) + best_cause_variable_id Int? + best_effect_variable_id Int? + user_maximum_allowed_daily_value Float? + user_minimum_allowed_daily_value Float? + user_minimum_allowed_non_zero_value Float? + minimum_allowed_seconds_between_measurements Int? + average_seconds_between_measurements Int? + median_seconds_between_measurements Int? + last_correlated_at DateTime? @db.Timestamp(0) + number_of_measurements_with_tags_at_last_correlation Int? + analysis_settings_modified_at DateTime? @db.Timestamp(0) + newest_data_at DateTime? @db.Timestamp(0) + analysis_requested_at DateTime? @db.Timestamp(0) + reason_for_analysis String? @db.VarChar(255) + analysis_started_at DateTime? @db.Timestamp(0) + analysis_ended_at DateTime? @db.Timestamp(0) + user_error_message String? + internal_error_message String? + earliest_source_measurement_start_at DateTime? @db.Timestamp(0) + latest_source_measurement_start_at DateTime? @db.Timestamp(0) + latest_tagged_measurement_start_at DateTime? @db.Timestamp(0) + earliest_tagged_measurement_start_at DateTime? @db.Timestamp(0) + latest_non_tagged_measurement_start_at DateTime? @db.Timestamp(0) + earliest_non_tagged_measurement_start_at DateTime? @db.Timestamp(0) + dfda_post_id BigInt? + number_of_soft_deleted_measurements Int? + best_user_correlation_id Int? + number_of_measurements Int? + number_of_tracking_reminder_notifications Int? + deletion_reason String? @db.VarChar(280) + record_size_in_kb Int? + number_of_common_tags Int? + number_common_tagged_by Int? + number_of_common_joined_variables Int? + number_of_common_ingredients Int? + number_of_common_foods Int? + number_of_common_children Int? + number_of_common_parents Int? + number_of_user_tags Int? + number_user_tagged_by Int? + number_of_user_joined_variables Int? + number_of_user_ingredients Int? + number_of_user_foods Int? + number_of_user_children Int? + number_of_user_parents Int? + is_public Boolean? + slug String? @unique(map: "user_variables_slug_uindex") @db.VarChar(200) + is_goal String? @db.VarChar(255) + controllable String? @db.VarChar(255) + boring Boolean? + predictor Boolean? + user_variable_relationships_user_variable_relationships_cause_user_variable_idTouser_variables user_variable_relationships[] @relation("user_variable_relationships_cause_user_variable_idTouser_variables") + user_variable_relationships_user_variable_relationships_effect_user_variable_idTouser_variables user_variable_relationships[] @relation("user_variable_relationships_effect_user_variable_idTouser_variables") + measurements measurements[] + tracking_reminder_notifications tracking_reminder_notifications[] + tracking_reminders_tracking_reminders_user_id_variable_idTouser_variables tracking_reminders[] @relation("tracking_reminders_user_id_variable_idTouser_variables") + tracking_reminders_tracking_reminders_user_variable_idTouser_variables tracking_reminders[] @relation("tracking_reminders_user_variable_idTouser_variables") + user_studies_user_studies_cause_user_variable_idTouser_variables user_studies[] @relation("user_studies_cause_user_variable_idTouser_variables") + user_studies_user_studies_effect_user_variable_idTouser_variables user_studies[] @relation("user_studies_effect_user_variable_idTouser_variables") + user_tags_user_tags_tag_user_variable_idTouser_variables user_tags[] @relation("user_tags_tag_user_variable_idTouser_variables") + user_tags_user_tags_tagged_user_variable_idTouser_variables user_tags[] @relation("user_tags_tagged_user_variable_idTouser_variables") + user_variable_clients user_variable_clients[] + user_variable_outcome_category user_variable_outcome_category[] + user_variable_predictor_category user_variable_predictor_category[] + oa_clients oa_clients? @relation(fields: [client_id], references: [client_id], onDelete: NoAction, onUpdate: NoAction, map: "user_variables_client_id_fk") + user_variable_relationships_user_variables_best_user_correlation_idTouser_variable_relationships user_variable_relationships? @relation("user_variables_best_user_correlation_idTouser_variable_relationships", fields: [best_user_correlation_id], references: [id], onUpdate: NoAction, map: "user_variables_user_variable_relationships_qm_score_fk") + units_user_variables_default_unit_idTounits units? @relation("user_variables_default_unit_idTounits", fields: [default_unit_id], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "user_variables_default_unit_id_fk") + units_user_variables_last_unit_idTounits units? @relation("user_variables_last_unit_idTounits", fields: [last_unit_id], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "user_variables_last_unit_id_fk") + dfda_users dfda_users @relation(fields: [user_id], references: [ID], onDelete: NoAction, onUpdate: NoAction, map: "user_variables_user_id_fk") + variable_categories variable_categories? @relation(fields: [variable_category_id], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "user_variables_variable_category_id_fk") + variables global_variables @relation(fields: [variable_id], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "user_variables_variables_id_fk") + + @@unique([user_id, variable_id], map: "uv_user_id") + @@index([variable_id], map: "fk_variableSettings") + @@index([analysis_started_at], map: "user_variables_analysis_started_at_index") + @@index([client_id], map: "user_variables_client_id_fk") + @@index([best_user_correlation_id], map: "user_variables_user_variable_relationships_qm_score_fk") + @@index([default_unit_id], map: "user_variables_default_unit_id_fk") + @@index([user_id], map: "user_variables_user_id_latest_tagged_measurement_time_index") + @@index([variable_category_id], map: "user_variables_variable_category_id_fk") + @@index([dfda_post_id], map: "user_variables_dfda_posts_ID_fk") +} + + + +model variable_categories { + id Int @id @default(autoincrement()) @db.SmallInt + name String @db.VarChar(64) + filling_value Float? + maximum_allowed_value Float? + minimum_allowed_value Float? + duration_of_action Int @default(86400) + onset_delay Int @default(0) + combination_operation String @default("SUM") @db.VarChar(255) + cause_only Boolean @default(false) + outcome Boolean? + created_at DateTime @default(now()) @db.Timestamp(0) + updated_at DateTime @default(now()) @db.Timestamp(0) + image_url String? + default_unit_id Int? @default(12) @db.SmallInt + deleted_at DateTime? @db.Timestamp(0) + manual_tracking Boolean? @default(false) + minimum_allowed_seconds_between_measurements Int? + average_seconds_between_measurements Int? + median_seconds_between_measurements Int? + dfda_post_id BigInt? + filling_type String? @db.VarChar(255) + number_of_outcome_population_studies Int? + number_of_predictor_population_studies Int? + number_of_outcome_case_studies Int? + number_of_predictor_case_studies Int? + number_of_measurements Int? + number_of_user_variables Int? + number_of_variables Int? + is_public Boolean? + synonyms String @db.VarChar(600) + amazon_product_category String @db.VarChar(100) + boring Boolean? + effect_only Boolean? + predictor Boolean? + font_awesome String? @db.VarChar(100) + ion_icon String? @db.VarChar(100) + more_info String? @db.VarChar(255) + valence String? @db.VarChar(255) + name_singular String @db.VarChar(255) + sort_order Int? + slug String @unique(map: "vc_slug_uindex") @db.VarChar(200) + is_goal String? @db.VarChar(255) + controllable String? @db.VarChar(255) + string_id String? @db.VarChar(64) + description String? @db.VarChar(255) + global_variable_relationships_global_variable_relationships_cause_variable_category_idTovariable_categories global_variable_relationships[] @relation("global_variable_relationships_cause_variable_category_idTovariable_categories") + global_variable_relationships_global_variable_relationships_effect_variable_category_idTovariable_categories global_variable_relationships[] @relation("global_variable_relationships_effect_variable_category_idTovariable_categories") + cohort_study_statistics_cohort_study_statistics_cause_variable_category_idTovariable_categories cohort_study_statistics[] @relation("cohort_study_statistics_cause_variable_category_idTovariable_categories") + cohort_study_statistics_cohort_study_statistics_effect_variable_category_idTovariable_categories cohort_study_statistics[] @relation("cohort_study_statistics_effect_variable_category_idTovariable_categories") + user_variable_relationships user_variable_relationships[] + measurements measurements[] + user_variable_outcome_category user_variable_outcome_category[] + user_variable_predictor_category user_variable_predictor_category[] + user_variables user_variables[] + variable_outcome_category variable_outcome_category[] + variable_predictor_category variable_predictor_category[] + variables global_variables[] + units units? @relation(fields: [unitsId], references: [id]) + unitsId Int? @db.SmallInt + + @@index([default_unit_id], map: "variable_categories_default_unit_id_fk") + @@index([dfda_post_id], map: "variable_categories_dfda_posts_ID_fk") +} + +/// This model has constraints using non-default deferring rules and requires additional setup for migrations. Visit https://pris.ly/d/constraint-deferring for more info. +model variable_outcome_category { + id Int @id @default(autoincrement()) + variable_id Int + variable_category_id Int @db.SmallInt + number_of_outcome_variables Int + created_at DateTime @default(now()) @db.Timestamp(0) + updated_at DateTime @default(now()) @db.Timestamp(0) + deleted_at DateTime? @db.Timestamp(0) + variable_categories variable_categories @relation(fields: [variable_category_id], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "variable_outcome_category_variable_categories_id_fk") + variables global_variables @relation(fields: [variable_id], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "variable_outcome_category_variables_id_fk") + + @@unique([variable_id, variable_category_id], map: "variable_outcome_category_uindex") + @@index([variable_category_id], map: "v_outcome_category_variable_categories_id_fk") +} + +/// This model has constraints using non-default deferring rules and requires additional setup for migrations. Visit https://pris.ly/d/constraint-deferring for more info. +model variable_predictor_category { + id Int @id @default(autoincrement()) + variable_id Int + variable_category_id Int @db.SmallInt + number_of_predictor_variables Int + created_at DateTime @default(now()) @db.Timestamp(0) + updated_at DateTime @default(now()) @db.Timestamp(0) + variable_categories variable_categories @relation(fields: [variable_category_id], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "variable_predictor_category_variable_categories_id_fk") + variables global_variables @relation(fields: [variable_id], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "variable_predictor_category_variables_id_fk") +} + + + +model global_variables { + id Int @id @default(autoincrement()) + name String @unique(map: "variables_name_UNIQUE") @db.VarChar(125) + number_of_user_variables Int @default(0) + variable_category_id Int @db.SmallInt + default_unit_id Int @db.SmallInt + default_value Float? + cause_only Boolean? + client_id String? @db.VarChar(80) + combination_operation String? @db.VarChar(255) + common_alias String? @db.VarChar(125) + created_at DateTime @default(now()) @db.Timestamp(0) + description String? + duration_of_action Int? + filling_value Float? @default(-1) + image_url String? @db.VarChar(2083) + informational_url String? @db.VarChar(2083) + ion_icon String? @db.VarChar(40) + kurtosis Float? + maximum_allowed_value Float? + maximum_recorded_value Float? + mean Float? + median Float? + minimum_allowed_value Float? + minimum_recorded_value Float? + number_of_global_variable_relationships_as_cause Int? + most_common_original_unit_id Int? + most_common_value Float? + number_of_global_variable_relationships_as_effect Int? + number_of_unique_values Int? + onset_delay Int? + outcome Boolean? + parent_id Int? + price Float? + product_url String? @db.VarChar(2083) + second_most_common_value Float? + skewness Float? + standard_deviation Float? + status String @default("WAITING") @db.VarChar(25) + third_most_common_value Float? + updated_at DateTime @default(now()) @db.Timestamp(0) + variance Float? + most_common_connector_id Int? + synonyms String? @db.VarChar(600) + wikipedia_url String? @db.VarChar(2083) + brand_name String? @db.VarChar(125) + valence String? @db.VarChar(255) + wikipedia_title String? @db.VarChar(100) + number_of_tracking_reminders Int? + upc_12 String? @db.VarChar(255) + upc_14 String? @db.VarChar(255) + number_common_tagged_by Int? + number_of_common_tags Int? + deleted_at DateTime? @db.Timestamp(0) + most_common_source_name String? @db.VarChar(255) + data_sources_count String? + optimal_value_message String? @db.VarChar(500) + best_cause_variable_id Int? + best_effect_variable_id Int? + common_maximum_allowed_daily_value Float? + common_minimum_allowed_daily_value Float? + common_minimum_allowed_non_zero_value Float? + minimum_allowed_seconds_between_measurements Int? + average_seconds_between_measurements Int? + median_seconds_between_measurements Int? + number_of_raw_measurements_with_tags_joins_children Int? + additional_meta_data String? + manual_tracking Boolean? + analysis_settings_modified_at DateTime? @db.Timestamp(0) + newest_data_at DateTime? @db.Timestamp(0) + analysis_requested_at DateTime? @db.Timestamp(0) + reason_for_analysis String? @db.VarChar(255) + analysis_started_at DateTime? @db.Timestamp(0) + analysis_ended_at DateTime? @db.Timestamp(0) + user_error_message String? + internal_error_message String? + latest_tagged_measurement_start_at DateTime? @db.Timestamp(0) + earliest_tagged_measurement_start_at DateTime? @db.Timestamp(0) + latest_non_tagged_measurement_start_at DateTime? @db.Timestamp(0) + earliest_non_tagged_measurement_start_at DateTime? @db.Timestamp(0) + dfda_post_id BigInt? + number_of_soft_deleted_measurements Int? + charts Json? @db.Json + creator_user_id BigInt + best_aggregate_correlation_id Int? + filling_type String? @db.VarChar(255) + number_of_outcome_population_studies Int? + number_of_predictor_population_studies Int? + number_of_applications_where_outcome_variable Int? + number_of_applications_where_predictor_variable Int? + number_of_common_tags_where_tag_variable Int? + number_of_common_tags_where_tagged_variable Int? + number_of_outcome_case_studies Int? + number_of_measurements Int? + number_of_predictor_case_studies Int? + number_of_studies_where_cause_variable Int? + number_of_studies_where_effect_variable Int? + number_of_tracking_reminder_notifications Int? + number_of_user_tags_where_tag_variable Int? + number_of_user_tags_where_tagged_variable Int? + number_of_variables_where_best_cause_variable Int? + number_of_variables_where_best_effect_variable Int? + number_of_votes_where_cause_variable Int? + number_of_votes_where_effect_variable Int? + number_of_users_where_primary_outcome_variable Int? + deletion_reason String? @db.VarChar(280) + maximum_allowed_daily_value Float? + record_size_in_kb Int? + number_of_common_joined_variables Int? + number_of_common_ingredients Int? + number_of_common_foods Int? + number_of_common_children Int? + number_of_common_parents Int? + number_of_user_joined_variables Int? + number_of_user_ingredients Int? + number_of_user_foods Int? + number_of_user_children Int? + number_of_user_parents Int? + is_public Boolean? + sort_order Int? + slug String? @unique(map: "variables_slug_uindex") @db.VarChar(200) + is_goal String? @db.VarChar(255) + controllable String? @db.VarChar(255) + boring Boolean? + canonical_variable_id Int? + predictor Boolean? + source_url String? @db.VarChar(2083) + string_id String? @db.VarChar(125) + global_variable_relationships_global_variable_relationships_cause_variable_idTovariables global_variable_relationships[] @relation("global_variable_relationships_cause_variable_idTovariables") + global_variable_relationships_global_variable_relationships_effect_variable_idTovariables global_variable_relationships[] @relation("global_variable_relationships_effect_variable_idTovariables") + cohort_studies_cohort_studies_cause_variable_idTovariables cohort_studies[] @relation("cohort_studies_cause_variable_idTovariables") + cohort_studies_cohort_studies_effect_variable_idTovariables cohort_studies[] @relation("cohort_studies_effect_variable_idTovariables") + cohort_study_statistics_cohort_study_statistics_cause_variable_idTovariables cohort_study_statistics[] @relation("cohort_study_statistics_cause_variable_idTovariables") + cohort_study_statistics_cohort_study_statistics_effect_variable_idTovariables cohort_study_statistics[] @relation("cohort_study_statistics_effect_variable_idTovariables") + common_tags_common_tags_tag_variable_idTovariables common_tags[] @relation("common_tags_tag_variable_idTovariables") + common_tags_common_tags_tagged_variable_idTovariables common_tags[] @relation("common_tags_tagged_variable_idTovariables") + correlation_causality_votes_correlation_causality_votes_cause_variable_idTovariables correlation_causality_votes[] @relation("correlation_causality_votes_cause_variable_idTovariables") + correlation_causality_votes_correlation_causality_votes_effect_variable_idTovariables correlation_causality_votes[] @relation("correlation_causality_votes_effect_variable_idTovariables") + variable_relationship_usefulness_votes_variable_relationship_usefulness_votes_cause_variable_idTovariables variable_relationship_usefulness_votes[] @relation("variable_relationship_usefulness_votes_cause_variable_idTovariables") + variable_relationship_usefulness_votes_variable_relationship_usefulness_votes_effect_variable_idTovariables variable_relationship_usefulness_votes[] @relation("variable_relationship_usefulness_votes_effect_variable_idTovariables") + user_variable_relationships_user_variable_relationships_cause_variable_idTovariables user_variable_relationships[] @relation("user_variable_relationships_cause_variable_idTovariables") + user_variable_relationships_user_variable_relationships_effect_variable_idTovariables user_variable_relationships[] @relation("user_variable_relationships_effect_variable_idTovariables") + global_studies_global_studies_cause_variable_idTovariables global_studies[] @relation("global_studies_cause_variable_idTovariables") + global_studies_global_studies_effect_variable_idTovariables global_studies[] @relation("global_studies_effect_variable_idTovariables") + measurements measurements[] + tracking_reminder_notifications tracking_reminder_notifications[] + tracking_reminders tracking_reminders[] + user_studies_user_studies_cause_variable_idTovariables user_studies[] @relation("user_studies_cause_variable_idTovariables") + user_studies_user_studies_effect_variable_idTovariables user_studies[] @relation("user_studies_effect_variable_idTovariables") + user_tags user_tags[] + user_variable_clients user_variable_clients[] + user_variable_outcome_category user_variable_outcome_category[] + user_variable_predictor_category user_variable_predictor_category[] + user_variables user_variables[] + variable_outcome_category variable_outcome_category[] + variable_predictor_category variable_predictor_category[] + + global_variable_relationships_variables_best_aggregate_correlation_idToglobal_variable_relationships global_variable_relationships? @relation("variables_best_aggregate_correlation_idToglobal_variable_relationships", fields: [best_aggregate_correlation_id], references: [id], onUpdate: NoAction, map: "variables_global_variable_relationships_id_fk") + variables_variables_best_cause_variable_idTovariables global_variables? @relation("variables_best_cause_variable_idTovariables", fields: [best_cause_variable_id], references: [id], onUpdate: NoAction, map: "variables_best_cause_variable_id_fk") + other_variables_variables_best_cause_variable_idTovariables global_variables[] @relation("variables_best_cause_variable_idTovariables") + variables_variables_best_effect_variable_idTovariables global_variables? @relation("variables_best_effect_variable_idTovariables", fields: [best_effect_variable_id], references: [id], onUpdate: NoAction, map: "variables_best_effect_variable_id_fk") + other_variables_variables_best_effect_variable_idTovariables global_variables[] @relation("variables_best_effect_variable_idTovariables") + oa_clients oa_clients? @relation(fields: [client_id], references: [client_id], onDelete: NoAction, onUpdate: NoAction, map: "variables_client_id_fk") + units units @relation(fields: [default_unit_id], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "variables_default_unit_id_fk") + votes_votes_cause_variable_idTovariables votes[] @relation("votes_cause_variable_idTovariables") + votes_votes_effect_variable_idTovariables votes[] @relation("votes_effect_variable_idTovariables") + global_variable_relationships global_variable_relationships[] + variable_categories variable_categories? @relation(fields: [variable_categoriesId], references: [id]) + variable_categoriesId Int? @db.SmallInt + + @@index([variable_category_id, default_unit_id, name, number_of_user_variables, id], map: "IDX_cat_unit_public_name") + @@index([default_unit_id], map: "fk_variableDefaultUnit") + @@index([deleted_at, synonyms, number_of_user_variables], map: "public_deleted_at_synonyms_number_of_user_variables_index") + @@index([best_aggregate_correlation_id], map: "variables_global_variable_relationships_id_fk") + @@index([best_cause_variable_id], map: "variables_best_cause_variable_id_fk") + @@index([best_effect_variable_id], map: "variables_best_effect_variable_id_fk") + @@index([client_id], map: "variables_client_id_fk") + @@index([name, number_of_user_variables], map: "variables_public_name_number_of_user_variables_index") + @@index([dfda_post_id], map: "variables_dfda_posts_ID_fk") +} + +model votes { + id Int @id @default(autoincrement()) + client_id String? @db.VarChar(80) + user_id BigInt + value Int + created_at DateTime @default(now()) @db.Timestamp(0) + updated_at DateTime @default(now()) @db.Timestamp(0) + deleted_at DateTime? @db.Timestamp(0) + cause_variable_id Int + effect_variable_id Int + correlation_id Int? + aggregate_correlation_id Int? + is_public Boolean? + global_variable_relationships global_variable_relationships? @relation(fields: [aggregate_correlation_id], references: [id], onUpdate: NoAction, map: "votes_global_variable_relationships_id_fk") + variables_votes_cause_variable_idTovariables global_variables @relation("votes_cause_variable_idTovariables", fields: [cause_variable_id], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "votes_cause_variable_id_fk") + oa_clients oa_clients? @relation(fields: [client_id], references: [client_id], onDelete: NoAction, onUpdate: NoAction, map: "votes_client_id_fk") + user_variable_relationships user_variable_relationships? @relation(fields: [correlation_id], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "votes_user_variable_relationships_id_fk") + variables_votes_effect_variable_idTovariables global_variables @relation("votes_effect_variable_idTovariables", fields: [effect_variable_id], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "votes_effect_variable_id_fk_2") + dfda_users dfda_users @relation(fields: [user_id], references: [ID], onDelete: NoAction, onUpdate: NoAction, map: "votes_user_id_fk") + + @@unique([user_id, cause_variable_id, effect_variable_id], map: "votes_user_id_cause_variable_id_effect_variable_id_uindex") + @@index([aggregate_correlation_id], map: "votes_global_variable_relationships_id_fk") + @@index([cause_variable_id], map: "votes_cause_variable_id_index") + @@index([client_id], map: "votes_client_id_fk") + @@index([correlation_id], map: "votes_user_variable_relationships_id_fk") + @@index([effect_variable_id], map: "votes_effect_variable_id_index") +} + +model Account { + id String @id @default(cuid()) + userId String @map("user_id") + type String + provider String + providerAccountId String @map("provider_account_id") + refresh_token String? @db.Text + access_token String? @db.Text + expires_at Int? + token_type String? + scope String? + id_token String? @db.Text + session_state String? + createdAt DateTime @default(now()) @map("created_at") + updatedAt DateTime @updatedAt @map("updated_at") + user User @relation(fields: [userId], references: [id], onDelete: Cascade) + + @@unique([provider, providerAccountId]) + @@map("accounts") +} + +model Session { + id String @id @default(cuid()) + sessionToken String @unique @map("session_token") + userId String @map("user_id") + expires DateTime + user User @relation(fields: [userId], references: [id], onDelete: Cascade) + + @@map("sessions") +} + +model User { + id String @id @default(cuid()) + dfda_user_id Int? + dfda_access_token String? + dfda_refresh_token String? + dfda_expires_in Int? + dfda_scope String? + dfda_access_token_expires_at DateTime? + address String? + banned Boolean? + birthday DateTime? + city String? + countryCode String? @map("country_code") + createdAt DateTime @default(now()) @map("created_at") + deletedAt DateTime? @map("deleted_at") + email String? @unique + emailVerified DateTime? @map("email_verified") + emailValidated Boolean @default(false) @map("email_validated") + firstName String? @map("first_name") + gdprConsent Boolean @default(false) @map("gdpr_consent") + gender String? + image String? + ipAddress String? @map("ip_address") @db.VarChar(45) + language String? + lastName String? @map("last_name") + lastSignInAt BigInt? @map("last_sign_in_at") + name String? + newsletterSubscribed Boolean @default(false) @map("newsletter_subscribed") + phoneNumber String? @map("phone_number") + postalCode String? @map("postal_code") + referrerUserId String? @map("referrer_user_id") + stateProvince String? @map("state_province") + updatedAt DateTime @updatedAt @map("updated_at") + username String @unique @default(uuid()) + web3Wallet String? @map("web3_wallet") + unsafeMetadata Json? @map("unsafe_metadata") + publicMetadata Json? @map("public_metadata") + privateMetadata Json? @map("private_metadata") + accounts Account[] + sessions Session[] + + @@map("users") +} + +model VerificationToken { + identifier String + token String @unique + expires DateTime + + @@unique([identifier, token]) + @@map("verification_tokens") +} + +model dfda_users { + ID BigInt @id @default(autoincrement()) @db.UnsignedBigInt + cohort_studies cohort_studies[] + connections connections[] + connector_imports connector_imports[] + connector_requests connector_requests[] + correlation_causality_votes correlation_causality_votes[] + variable_relationship_usefulness_votes variable_relationship_usefulness_votes[] + user_variable_relationships user_variable_relationships[] + device_tokens device_tokens[] + global_studies global_studies[] + measurement_exports measurement_exports[] + measurement_imports measurement_imports[] + measurements measurements[] + phrases phrases[] + sent_emails sent_emails[] + tracking_reminder_notifications tracking_reminder_notifications[] + tracking_reminders tracking_reminders[] + user_studies user_studies[] + user_tags user_tags[] + user_variable_clients user_variable_clients[] + user_variables user_variables[] + votes votes[] +} + +model oa_clients { + client_id String @id @db.VarChar(80) + client_secret String @db.VarChar(80) + redirect_uri String? @db.VarChar(2000) + grant_types String? @db.VarChar(80) + user_id BigInt @db.UnsignedBigInt + created_at DateTime @default(now()) @db.Timestamp(0) + updated_at DateTime @default(now()) @db.Timestamp(0) + icon_url String? @db.VarChar(2083) + app_identifier String? @db.VarChar(255) + deleted_at DateTime? @db.Timestamp(0) + earliest_measurement_start_at DateTime? @db.Timestamp(0) + latest_measurement_start_at DateTime? @db.Timestamp(0) + number_of_global_variable_relationships Int? @db.UnsignedInt + number_of_applications Int? @db.UnsignedInt + number_of_oauth_access_tokens Int? @db.UnsignedInt + number_of_oauth_authorization_codes Int? @db.UnsignedInt + number_of_oauth_refresh_tokens Int? @db.UnsignedInt + number_of_button_clicks Int? @db.UnsignedInt + number_of_collaborators Int? @db.UnsignedInt + number_of_common_tags Int? @db.UnsignedInt + number_of_connections Int? @db.UnsignedInt + number_of_connector_imports Int? @db.UnsignedInt + number_of_connectors Int? @db.UnsignedInt + number_of_user_variable_relationships Int? @db.UnsignedInt + number_of_measurement_exports Int? @db.UnsignedInt + number_of_measurement_imports Int? @db.UnsignedInt + number_of_measurements Int? @db.UnsignedInt + number_of_sent_emails Int? @db.UnsignedInt + number_of_studies Int? @db.UnsignedInt + number_of_tracking_reminder_notifications Int? @db.UnsignedInt + number_of_tracking_reminders Int? @db.UnsignedInt + number_of_user_tags Int? @db.UnsignedInt + number_of_user_variables Int? @db.UnsignedInt + number_of_variables Int? @db.UnsignedInt + number_of_votes Int? @db.UnsignedInt + global_variable_relationships global_variable_relationships[] + cohort_studies cohort_studies[] + cohort_study_statistics cohort_study_statistics[] + common_tags common_tags[] + connections connections[] + connector_imports connector_imports[] + connectors connectors[] + correlation_causality_votes correlation_causality_votes[] + device_tokens device_tokens[] + global_studies global_studies[] + measurement_exports measurement_exports[] + measurement_imports measurement_imports[] + measurements measurements[] + phrases phrases[] + sent_emails sent_emails[] + spreadsheet_importers spreadsheet_importers[] + tracking_reminder_notifications tracking_reminder_notifications[] + tracking_reminders tracking_reminders[] + user_tags user_tags[] + user_variable_clients user_variable_clients[] + user_variables user_variables[] + variables global_variables[] + votes votes[] + variable_relationship_usefulness_votes variable_relationship_usefulness_votes[] + user_variable_relationships user_variable_relationships[] + + @@index([user_id], map: "oa_clients_user_id_fk") +} diff --git a/libs/db-schema/postgres/seedDB.js b/libs/db-schema/postgres/seedDB.js new file mode 100644 index 000000000..86c764766 --- /dev/null +++ b/libs/db-schema/postgres/seedDB.js @@ -0,0 +1,74 @@ +const sqlite3 = require('sqlite3').verbose(); +const mysql = require('mysql2/promise'); + + + +// Open the SQLite database +let db = new sqlite3.Database('./test_db.sqlite', sqlite3.OPEN_READONLY, (err) => { + if (err) { + console.error(err.message); + } + console.log('Connected to the SQLite database.'); +}); + +const path = require('path'); +require('dotenv').config({ path: path.resolve(__dirname, '../.env') }); +const url = require('url'); +let DATABASE_URL = process.env.DATABASE_URL; +// Parse the DATABASE_URL +let dbUrl = url.parse(DATABASE_URL); + +// Extract the user and password from the auth string +let [user, password] = dbUrl.auth.split(':'); + +// Extract the database name from the pathname +let database = dbUrl.pathname.replace('/', ''); + +// Extract the host and port from the host string +let [host, port] = dbUrl.host.split(':'); + +// Now you can use these variables to connect to your database +mysql.createConnection({ + host: host, + port: port, + user: user, + password: password, + database: database +}).then((conn) => { + console.log('Connected to the MySQL database.'); + + // Query the SQLite database for all table names +db.all("SELECT name FROM sqlite_master WHERE type='table'", [], (err, tables) => { + if (err) { + throw err; + } + + // For each table in the SQLite database + tables.forEach((table) => { + // Query the SQLite database for all rows in the current table + db.all(`SELECT * FROM ${table.name}`, [], (err, rows) => { + if (err) { + throw err; + } + + // For each row in the SQLite database, insert it into the MySQL database + rows.forEach((row) => { + conn.query(`INSERT INTO ${table.name} SET ?`, row, (err, res) => { + if (err) throw err; + console.log(`Inserted: ${res.insertId}`); + }); + }); + }); + }); +}); + + // Close the SQLite database connection + db.close((err) => { + if (err) { + console.error(err.message); + } + console.log('Close the SQLite database connection.'); + }); +}).catch((err) => { + console.error('Unable to connect to the MySQL database: ', err); +}); diff --git a/libs/db-schema/postgres/test_db.sqlite b/libs/db-schema/postgres/test_db.sqlite new file mode 100644 index 000000000..e59f0dee0 Binary files /dev/null and b/libs/db-schema/postgres/test_db.sqlite differ