Skip to content

Commit db7787e

Browse files
committed
Merge branch 'master' into FEAT-1193-allow-users-to-edit-exclusion-labels
2 parents 54b44dc + 19d2231 commit db7787e

File tree

68 files changed

+2878
-513
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

68 files changed

+2878
-513
lines changed

.github/workflows/deploy-to-staging.yml

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,6 @@ jobs:
7070
7171
# Wait for PostgreSQL to be ready
7272
until docker compose exec store-pgsql pg_isready; do sleep 5; done
73-
74-
docker compose exec neurostore flask db migrate
7573
docker compose exec neurostore flask db upgrade
7674
'
7775
@@ -86,8 +84,6 @@ jobs:
8684
8785
# Wait for PostgreSQL to be ready
8886
until docker compose exec compose_pgsql pg_isready; do sleep 5; done
89-
90-
docker compose exec compose flask db migrate
9187
docker compose exec compose flask db upgrade
9288
'
9389

.github/workflows/workflow.yml

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -473,39 +473,29 @@ jobs:
473473
474474
docker compose exec -T \
475475
compose_pgsql17 \
476-
psql -U postgres -c "create database test_db"
476+
psql -U postgres -c "CREATE DATABASE test_db"
477477
-
478478
name: Create Store Database
479479
run: |
480480
cd store
481481
482482
docker compose exec -T \
483483
store-pgsql17 \
484-
psql -U postgres -c "create database test_db"
484+
psql -U postgres -c "CREATE DATABASE test_db"
485485
486486
docker compose exec -T \
487487
store-pgsql17 \
488488
psql -U postgres -d test_db -c "CREATE EXTENSION IF NOT EXISTS vector;"
489489
-
490-
name: Initialize Compose Database
490+
name: Apply Compose migrations
491491
run: |
492492
cd compose
493-
docker compose exec -T compose \
494-
bash -c \
495-
"flask db merge heads && \
496-
flask db stamp head && \
497-
flask db migrate && \
498-
flask db upgrade"
493+
docker compose exec -T compose flask db upgrade
499494
-
500-
name: Initialize Store Database
495+
name: Apply Store migrations
501496
run: |
502497
cd store
503-
docker compose exec -T neurostore \
504-
bash -c \
505-
"flask db merge heads && \
506-
flask db stamp head && \
507-
flask db migrate && \
508-
flask db upgrade"
498+
docker compose exec -T neurostore flask db upgrade
509499
-
510500
name: Ingest data into Store
511501
run: |

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ instance/
7171
.webassets-cache
7272

7373
# Postgres Python migrations:
74-
**/backend/migrations/versions/*
74+
# **/backend/migrations/versions/*
7575

7676
# Scrapy stuff:
7777
.scrapy

compose/backend/README.md

Lines changed: 34 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -27,39 +27,57 @@ The server should now be running at http://localhost:81
2727

2828
Create the database for compose:
2929

30-
docker-compose exec compose_pgsql psql -U postgres -c "create database compose"
30+
docker-compose exec compose_pgsql17 psql -U postgres -c "create database compose"
3131

32-
Next, migrate and upgrade the database migrations.
32+
Next, apply the existing migrations (they are the canonical schema definition):
3333

34-
docker-compose exec compose \
35-
bash -c \
36-
"flask db merge heads && \
37-
flask db stamp head && \
38-
flask db migrate && \
39-
flask db upgrade"
40-
41-
**Note**: `flask db merge heads` is not strictly necessary
42-
unless you have multiple schema versions that are not from the same history
43-
(e.g., multiple files in the `versions` directory).
44-
However, `flask db merge heads` makes the migration more robust
45-
when there are multiple versions from different histories.
34+
docker-compose exec compose flask db upgrade
4635

4736

4837
## Maintaining docker image and db
4938
If you make a change to compose, you should be able to simply restart the server.
5039

5140
docker-compose restart compose
5241

53-
If you need to upgrade the db after changing any models:
42+
If you change any models, generate a new Alembic migration and migrate the database (commit the generated revision file so it becomes the new source of truth):
5443

5544
docker-compose exec compose flask db migrate
5645
docker-compose exec compose flask db upgrade
5746

5847

48+
## Database migrations
49+
50+
The migrations stored in `backend/migrations` are the **only** source of truth for the schema—avoid merging heads, stamping, or manually altering the history. Always move the database forward (or rebuild from scratch) by applying the tracked revisions.
51+
52+
### Applying migrations after pulling a branch
53+
54+
Any time you start the backend or pull the latest changes, bring the database to the expected state with:
55+
56+
```sh
57+
docker-compose exec compose flask db upgrade
58+
```
59+
60+
`upgrade` is idempotent, so rerunning it is harmless; it only applies migrations that have not been run yet.
61+
62+
### Resetting the database when switching branches
63+
64+
Because each branch might change the schema independently, recreate the database before starting work on a different branch so that Alembic can replay only the migrations that exist on that branch.
65+
66+
```sh
67+
docker-compose stop compose
68+
docker-compose exec compose_pgsql17 psql -U postgres -c "DROP DATABASE IF EXISTS compose;"
69+
docker-compose exec compose_pgsql17 psql -U postgres -c "CREATE DATABASE compose;"
70+
docker-compose start compose
71+
docker-compose exec compose flask db upgrade
72+
```
73+
74+
If you're using the legacy Postgres container, replace `compose_pgsql17` with `compose_pgsql` in the commands above.
75+
76+
5977
## Running tests
6078
To run tests, after starting services, create a test database:
6179

62-
docker-compose exec compose_pgsql psql -U postgres -c "create database test_db"
80+
docker-compose exec compose_pgsql17 psql -U postgres -c "create database test_db"
6381

6482
**NOTE**: This command will ask you for the postgres password which is defined
6583
in the `.env` file.

compose/backend/manage.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@
1414
from neurosynth_compose.database import db
1515
from neurosynth_compose import models
1616
from neurosynth_compose.ingest import neurostore as ingest_nstore
17+
from neurosynth_compose.scripts.backfill_extraction_metadata import (
18+
add_missing_extraction_ids,
19+
)
1720

1821

1922
app.config.from_object(os.environ["APP_SETTINGS"])
@@ -44,3 +47,12 @@ def create_meta_analyses(n_studysets, neurostore_url):
4447
if n_studysets is not None:
4548
n_studysets = int(n_studysets)
4649
ingest_nstore.create_meta_analyses(url=neurostore_url, n_studysets=n_studysets)
50+
51+
52+
@app.cli.command("backfill-extraction-metadata")
53+
def backfill_extraction_metadata():
54+
"""Add missing extractionMetadata ids to project provenance."""
55+
updated, skipped = add_missing_extraction_ids()
56+
click.echo(
57+
f"Updated {updated} project(s); skipped {skipped} project(s) with no changes."
58+
)
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
"""empty message
2+
3+
Revision ID: 0717f5de725b
4+
Revises: c1fb13263539
5+
Create Date: 2023-12-12 22:59:12.319399
6+
7+
"""
8+
from alembic import op
9+
import sqlalchemy as sa
10+
import sqlalchemy_utils
11+
12+
13+
# revision identifiers, used by Alembic.
14+
revision = '0717f5de725b'
15+
down_revision = 'c1fb13263539'
16+
branch_labels = None
17+
depends_on = None
18+
19+
20+
def upgrade():
21+
# ### commands auto generated by Alembic - please adjust! ###
22+
op.add_column('specification_conditions', sa.Column('user_id', sa.Text(), nullable=True))
23+
op.create_foreign_key(None, 'specification_conditions', 'users', ['user_id'], ['external_id'])
24+
op.add_column('specifications', sa.Column('database_studyset', sa.Text(), nullable=True))
25+
# ### end Alembic commands ###
26+
27+
28+
def downgrade():
29+
# ### commands auto generated by Alembic - please adjust! ###
30+
op.drop_column('specifications', 'database_studyset')
31+
op.drop_constraint(None, 'specification_conditions', type_='foreignkey')
32+
op.drop_column('specification_conditions', 'user_id')
33+
# ### end Alembic commands ###
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
"""empty message
2+
3+
Revision ID: 164fb969f549
4+
Revises: e1c296d89bf1
5+
Create Date: 2023-05-18 19:15:07.407065
6+
7+
"""
8+
from alembic import op
9+
import sqlalchemy as sa
10+
import sqlalchemy_utils
11+
12+
13+
# revision identifiers, used by Alembic.
14+
revision = '164fb969f549'
15+
down_revision = 'e1c296d89bf1'
16+
branch_labels = None
17+
depends_on = None
18+
19+
20+
def upgrade():
21+
# ### commands auto generated by Alembic - please adjust! ###
22+
op.add_column('meta_analysis_results', sa.Column('diagnostic_table', sa.Text(), nullable=True))
23+
# ### end Alembic commands ###
24+
25+
26+
def downgrade():
27+
# ### commands auto generated by Alembic - please adjust! ###
28+
op.drop_column('meta_analysis_results', 'diagnostic_table')
29+
# ### end Alembic commands ###
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
"""empty message
2+
3+
Revision ID: 26aa47ee8e3e
4+
Revises: 76c16b00a2bc
5+
Create Date: 2022-12-16 18:22:04.536097
6+
7+
"""
8+
from alembic import op
9+
import sqlalchemy as sa
10+
import sqlalchemy_utils
11+
12+
13+
# revision identifiers, used by Alembic.
14+
revision = '26aa47ee8e3e'
15+
down_revision = '76c16b00a2bc'
16+
branch_labels = None
17+
depends_on = None
18+
19+
20+
def upgrade():
21+
# ### commands auto generated by Alembic - please adjust! ###
22+
op.create_table('projects',
23+
sa.Column('id', sa.Text(), nullable=False),
24+
sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=True),
25+
sa.Column('updated_at', sa.DateTime(timezone=True), nullable=True),
26+
sa.Column('name', sa.Text(), nullable=True),
27+
sa.Column('description', sa.Text(), nullable=True),
28+
sa.Column('provenance', sa.JSON(), nullable=True),
29+
sa.Column('user_id', sa.Text(), nullable=True),
30+
sa.ForeignKeyConstraint(['user_id'], ['users.external_id'], ),
31+
sa.PrimaryKeyConstraint('id')
32+
)
33+
op.add_column('meta_analyses', sa.Column('project_id', sa.Text(), nullable=True))
34+
op.add_column('meta_analyses', sa.Column('provenance', sa.JSON(), nullable=True))
35+
op.create_foreign_key(None, 'meta_analyses', 'projects', ['project_id'], ['id'])
36+
# ### end Alembic commands ###
37+
38+
39+
def downgrade():
40+
# ### commands auto generated by Alembic - please adjust! ###
41+
op.drop_constraint(None, 'meta_analyses', type_='foreignkey')
42+
op.drop_column('meta_analyses', 'provenance')
43+
op.drop_column('meta_analyses', 'project_id')
44+
op.drop_table('projects')
45+
# ### end Alembic commands ###
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
"""empty message
2+
3+
Revision ID: 28251f5cb6d5
4+
Revises: 3d0fc483f06b
5+
Create Date: 2025-10-13 19:11:58.785877
6+
7+
"""
8+
from alembic import op
9+
import sqlalchemy as sa
10+
import sqlalchemy_utils
11+
12+
13+
# revision identifiers, used by Alembic.
14+
revision = '28251f5cb6d5'
15+
down_revision = '3d0fc483f06b'
16+
branch_labels = None
17+
depends_on = None
18+
19+
20+
def upgrade():
21+
# ### commands auto generated by Alembic - please adjust! ###
22+
with op.batch_alter_table('projects', schema=None) as batch_op:
23+
batch_op.add_column(sa.Column('studyset_id', sa.Text(), nullable=True))
24+
batch_op.add_column(sa.Column('annotation_id', sa.Text(), nullable=True))
25+
batch_op.create_foreign_key(None, 'annotations', ['annotation_id'], ['id'])
26+
batch_op.create_foreign_key(None, 'studysets', ['studyset_id'], ['id'])
27+
28+
# ### end Alembic commands ###
29+
30+
31+
def downgrade():
32+
# ### commands auto generated by Alembic - please adjust! ###
33+
with op.batch_alter_table('projects', schema=None) as batch_op:
34+
batch_op.drop_constraint(None, type_='foreignkey')
35+
batch_op.drop_constraint(None, type_='foreignkey')
36+
batch_op.drop_column('annotation_id')
37+
batch_op.drop_column('studyset_id')
38+
39+
# ### end Alembic commands ###
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
"""empty message
2+
3+
Revision ID: 3d0fc483f06b
4+
Revises: 52eabbbdffe6
5+
Create Date: 2025-08-21 22:16:48.621497
6+
7+
"""
8+
from alembic import op
9+
import sqlalchemy as sa
10+
import sqlalchemy_utils
11+
12+
13+
# revision identifiers, used by Alembic.
14+
revision = '3d0fc483f06b'
15+
down_revision = '52eabbbdffe6'
16+
branch_labels = None
17+
depends_on = None
18+
19+
20+
def upgrade():
21+
# ### commands auto generated by Alembic - please adjust! ###
22+
op.create_index(op.f('ix_projects_draft'), 'projects', ['draft'], unique=False)
23+
op.create_index(op.f('ix_projects_public'), 'projects', ['public'], unique=False)
24+
op.create_index(op.f('ix_projects_user_id'), 'projects', ['user_id'], unique=False)
25+
# ### end Alembic commands ###
26+
27+
28+
def downgrade():
29+
# ### commands auto generated by Alembic - please adjust! ###
30+
op.drop_index(op.f('ix_projects_user_id'), table_name='projects')
31+
op.drop_index(op.f('ix_projects_public'), table_name='projects')
32+
op.drop_index(op.f('ix_projects_draft'), table_name='projects')
33+
# ### end Alembic commands ###

0 commit comments

Comments
 (0)