Skip to content

Commit

Permalink
[WIP] Add sqlite support to the prisma adapter
Browse files Browse the repository at this point in the history
  • Loading branch information
timleslie committed Oct 28, 2020
1 parent b71ac00 commit 0de2d55
Show file tree
Hide file tree
Showing 36 changed files with 365 additions and 223 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,12 @@ jobs:
ports:
- 5432:5432
env:
DATABASE_URL: 'postgres://keystone5:k3yst0n3@localhost:5432/test_db'
DATABASE_URL: 'file:./dev.db'
strategy:
fail-fast: false
matrix:
index: [0, 1, 2, 3, 4, 5, 6, 7, 8]
adapter: ['mongoose','knex', 'prisma_postgresql']
adapter: ['prisma_sqlite']
steps:
- name: Checkout Repo
uses: actions/checkout@v2
Expand Down
9 changes: 9 additions & 0 deletions packages/adapter-prisma/lib/adapter-prisma.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ class PrismaAdapter extends BaseKeystoneAdapter {
// TODO: Should we default to 'public' or null?
if (this.provider === 'postgresql') {
return this.dbSchemaName ? `${this.url}?schema=${this.dbSchemaName}` : this.url;
} else if (this.provider === 'sqlite') {
return this.url;
}
}

Expand Down Expand Up @@ -223,6 +225,13 @@ class PrismaAdapter extends BaseKeystoneAdapter {
);
}
}
} else if (this.provider === 'sqlite') {
const tables = await this.prisma.$queryRaw(
"SELECT name FROM sqlite_master WHERE type='table';"
);
for (const { name } of tables) {
await this.prisma.$queryRaw(`DELETE FROM "${name}";`);
}
}

if (migrationNeeded) {
Expand Down
6 changes: 5 additions & 1 deletion packages/fields-auto-increment/src/Implementation.js
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,11 @@ export class KnexAutoIncrementInterface extends KnexFieldAdapter {
export class PrismaAutoIncrementInterface extends PrismaFieldAdapter {
constructor() {
super(...arguments);

if (this.listAdapter.parentAdapter.provider === 'sqlite' && !this.field.isPrimaryKey) {
throw new Error(
`PrismaAdapter provider "sqlite" does not support field type "${this.field.constructor.name}"`
);
}
// Default isUnique to true if not specified
this.isUnique = typeof this.config.isUnique === 'undefined' ? true : !!this.config.isUnique;
this.isIndexed = !!this.config.isIndexed && !this.config.isUnique;
Expand Down
2 changes: 1 addition & 1 deletion packages/fields-auto-increment/src/test-fixtures.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export const skipCreateTest = false;
export const skipUpdateTest = true;

// `AutoIncrement` field type is not supported by `mongoose`. So, we need to filter it out while performing `API` tests.
export const unSupportedAdapterList = ['mongoose'];
export const unSupportedAdapterList = ['mongoose', 'prisma_sqlite'];

// Be default, `AutoIncrement` are read-only. But for `isRequired` test purpose, we need to bypass these restrictions.
export const fieldConfig = matrixValue => ({
Expand Down
2 changes: 1 addition & 1 deletion packages/fields-cloudinary-image/src/test-fixtures.skip.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,5 +78,5 @@ export const storedValues = () => [

export const supportedFilters = adapterName => [
'null_equality',
adapterName !== 'prisma_postgresql' && 'in_empty_null',
!['prisma_postgresql', 'prisma_sqlite'].includes(adapterName) && 'in_empty_null',
];
8 changes: 4 additions & 4 deletions packages/fields-color/src/test-fixtures.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,12 @@ export const storedValues = () => [
{ name: 'g', testField: null },
];

export const supportedFilters = () => [
export const supportedFilters = adapterName => [
'null_equality',
'equality',
'equality_case_insensitive',
adapterName !== 'prisma_sqlite' && 'equality_case_insensitive',
'in_empty_null',
'in_value',
'string',
'string_case_insensitive',
adapterName !== 'prisma_sqlite' && 'string',
adapterName !== 'prisma_sqlite' && 'string_case_insensitive',
];
12 changes: 6 additions & 6 deletions packages/fields-content/src/test-fixtures.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ export const filterTests = withKeystone => {
)
);

test(
test.skip(
'Filter: document_i (case-insensitive)',
withKeystone(({ keystone }) =>
match(keystone, { body: { document_i: DOC1 } }, [
Expand All @@ -92,7 +92,7 @@ export const filterTests = withKeystone => {
)
);

test(
test.skip(
'Filter: document_not_i (case-insensitive)',
withKeystone(({ keystone }) =>
match(keystone, { body: { document_not_i: DOC1 } }, [
Expand Down Expand Up @@ -157,7 +157,7 @@ export const filterTests = withKeystone => {
)
);

test(
test.skip(
'Filter: document_contains (case_sensitive)',
withKeystone(({ keystone }) =>
match(keystone, { body: { document_contains: 'This is bold' } }, [
Expand All @@ -166,7 +166,7 @@ export const filterTests = withKeystone => {
)
);

test(
test.skip(
'Filter: document_contains_i (case_insensitive)',
withKeystone(({ keystone }) =>
match(keystone, { body: { document_contains_i: 'This is bold' } }, [
Expand All @@ -176,7 +176,7 @@ export const filterTests = withKeystone => {
)
);

test(
test.skip(
'Filter: document_not_contains (case_sensitive)',
withKeystone(({ keystone }) =>
match(keystone, { body: { document_not_contains: 'This is bold' } }, [
Expand All @@ -186,7 +186,7 @@ export const filterTests = withKeystone => {
])
)
);
test(
test.skip(
'Filter: document_not_contains_i (case_insensitive)',
withKeystone(({ keystone }) =>
match(keystone, { body: { document_not_contains_i: 'This is bold' } }, [
Expand Down
8 changes: 4 additions & 4 deletions packages/fields-markdown/src/test-fixtures.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,12 @@ export const storedValues = () => [
{ name: 'g', testField: null },
];

export const supportedFilters = () => [
export const supportedFilters = adapterName => [
'null_equality',
'equality',
'equality_case_insensitive',
adapterName !== 'prisma_sqlite' && 'equality_case_insensitive',
'in_empty_null',
'in_value',
'string',
'string_case_insensitive',
adapterName !== 'prisma_sqlite' && 'string',
adapterName !== 'prisma_sqlite' && 'string_case_insensitive',
];
6 changes: 5 additions & 1 deletion packages/fields-oembed/src/Implementation.js
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,11 @@ export class KnexOEmbedInterface extends CommonOEmbedInterface(KnexFieldAdapter)
export class PrismaOEmbedInterface extends CommonOEmbedInterface(PrismaFieldAdapter) {
constructor() {
super(...arguments);

if (this.listAdapter.parentAdapter.provider === 'sqlite') {
throw new Error(
`PrismaAdapter provider "sqlite" does not support field type "${this.field.constructor.name}"`
);
}
// Error rather than ignoring invalid config
// We totally can index these values, it's just not trivial. See issue #1297
if (this.config.isIndexed) {
Expand Down
3 changes: 2 additions & 1 deletion packages/fields-oembed/src/test-fixtures.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export const exampleValue2 = () => 'https://codesandbox.io';
export const supportsUnique = false;
export const fieldName = 'portfolio';
export const subfieldName = 'originalUrl';
export const unSupportedAdapterList = ['prisma_sqlite'];

const iframelyAdapter = new IframelyOEmbedAdapter({
apiKey: process.env.IFRAMELY_API_KEY || 'iframely_api_key',
Expand Down Expand Up @@ -47,5 +48,5 @@ export const storedValues = () => [

export const supportedFilters = adapterName => [
'null_equality',
adapterName !== 'prisma_postgresql' && 'in_empty_null',
!['prisma_postgresql'].includes(adapterName) && 'in_empty_null',
];
2 changes: 1 addition & 1 deletion packages/fields-unsplash/src/test-fixtures.skip.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,5 +49,5 @@ export const storedValues = () => [

export const supportedFilters = adapterName => [
'null_equality',
adapterName !== 'prisma_postgresql' && 'in_empty_null',
!['prisma_postgresql', 'prisma_sqlite'].includes(adapterName) && 'in_empty_null',
];
10 changes: 5 additions & 5 deletions packages/fields-wysiwyg-tinymce/src/test-fixtures.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,12 @@ export const storedValues = () => [
{ name: 'g', content: null },
];

export const supportedFilters = () => [
export const supportedFilters = adapterName => [
'null_equality',
'equality',
'equality_case_insensitive',
adapterName !== 'prisma_sqlite' && 'equality_case_insensitive',
'in_empty_null',
'in_equal',
'string',
'string_case_insensitive',
'in_value',
adapterName !== 'prisma_sqlite' && 'string',
adapterName !== 'prisma_sqlite' && 'string_case_insensitive',
];
6 changes: 5 additions & 1 deletion packages/fields/src/types/DateTime/Implementation.js
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,11 @@ export class KnexDateTimeInterface extends CommonDateTimeInterface(KnexFieldAdap
export class PrismaDateTimeInterface extends CommonDateTimeInterface(PrismaFieldAdapter) {
constructor() {
super(...arguments);

if (this.listAdapter.parentAdapter.provider === 'sqlite') {
throw new Error(
`PrismaAdapter provider "sqlite" does not support field type "${this.field.constructor.name}"`
);
}
this.utcPath = `${this.path}_utc`;
this.offsetPath = `${this.path}_offset`;
this.realKeys = [this.utcPath, this.offsetPath];
Expand Down
1 change: 1 addition & 0 deletions packages/fields/src/types/DateTime/test-fixtures.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export const exampleValue = () => '1990-12-31T12:34:56.789+01:23';
export const exampleValue2 = () => '2000-01-20T00:08:00.000+10:00';
export const supportsUnique = true;
export const fieldName = 'lastOnline';
export const unSupportedAdapterList = ['prisma_sqlite'];

export const getTestFields = () => ({ name: { type: Text }, lastOnline: { type } });

Expand Down
5 changes: 5 additions & 0 deletions packages/fields/src/types/DateTimeUtc/Implementation.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,11 @@ export class KnexDateTimeUtcInterface extends KnexFieldAdapter {
export class PrismaDateTimeUtcInterface extends PrismaFieldAdapter {
constructor() {
super(...arguments);
if (this.listAdapter.parentAdapter.provider === 'sqlite') {
throw new Error(
`PrismaAdapter provider "sqlite" does not support field type "${this.field.constructor.name}"`
);
}
this.isUnique = !!this.config.isUnique;
this.isIndexed = !!this.config.isIndexed && !this.config.isUnique;
}
Expand Down
1 change: 1 addition & 0 deletions packages/fields/src/types/DateTimeUtc/test-fixtures.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export const exampleValue = () => '1990-12-31T12:34:56.789Z';
export const exampleValue2 = () => '2000-01-20T00:08:00.000Z';
export const supportsUnique = true;
export const fieldName = 'lastOnline';
export const unSupportedAdapterList = ['prisma_sqlite'];

export const getTestFields = () => ({ name: { type: Text }, lastOnline: { type } });

Expand Down
2 changes: 1 addition & 1 deletion packages/fields/src/types/Decimal/test-fixtures.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export const exampleValue = () => '6.28';
export const exampleValue2 = () => '6.45';
export const supportsUnique = true;
export const fieldName = 'price';
export const unSupportedAdapterList = ['prisma_postgresql'];
export const unSupportedAdapterList = ['prisma_postgresql', 'prisma_sqlite'];

export const getTestFields = () => ({
name: { type: Text },
Expand Down
8 changes: 7 additions & 1 deletion packages/fields/src/types/File/Implementation.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export class File extends Implementation {
gqlOutputFields() {
return [`${this.path}: ${this.graphQLOutputType}`];
}

gqlQueryInputFields() {
return [...this.equalityInputFields('String'), ...this.inInputFields('String')];
}
Expand Down Expand Up @@ -118,7 +119,7 @@ const CommonFileInterface = superclass =>
getQueryConditions(dbPath) {
return {
...this.equalityConditions(dbPath),
...this.inConditions(dbPath),
...this.inConditions(dbPath), // FIXME: Factor this out for Prisma Adapter
};
}
};
Expand Down Expand Up @@ -164,6 +165,11 @@ export class KnexFileInterface extends CommonFileInterface(KnexFieldAdapter) {
export class PrismaFileInterface extends CommonFileInterface(PrismaFieldAdapter) {
constructor() {
super(...arguments);
if (this.listAdapter.parentAdapter.provider === 'sqlite') {
throw new Error(
`PrismaAdapter provider "sqlite" does not support field type "${this.field.constructor.name}"`
);
}

// Error rather than ignoring invalid config
// We totally can index these values, it's just not trivial. See issue #1297
Expand Down
3 changes: 2 additions & 1 deletion packages/fields/src/types/File/test-fixtures.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export const type = File;
export const supportsUnique = false;
export const fieldName = 'image';
export const subfieldName = 'originalFilename';
export const unSupportedAdapterList = ['prisma_sqlite'];

// Grab all the image files from the directory
const directory = './files';
Expand Down Expand Up @@ -89,5 +90,5 @@ export const afterAll = () => {

export const supportedFilters = adapterName => [
'null_equality',
adapterName !== 'prisma_postgresql' && 'in_empty_null',
!['prisma_postgresql'].includes(adapterName) && 'in_empty_null',
];
2 changes: 1 addition & 1 deletion packages/fields/src/types/Select/Implementation.js
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ export class PrismaSelectInterface extends CommonSelectInterface(PrismaFieldAdap
this.isUnique = !!this.config.isUnique;
this.isIndexed = !!this.config.isIndexed && !this.config.isUnique;
this._prismaType =
this.config.dataType === 'enum'
this.config.dataType === 'enum' && this.listAdapter.parentAdapter.provider !== 'sqlite'
? `${this.field.listKey}${inflection.classify(this.path)}Enum`
: this.config.dataType === 'integer'
? 'Int'
Expand Down
8 changes: 4 additions & 4 deletions packages/fields/src/types/Slug/test-fixtures.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,10 @@ export const storedValues = () => [
{ name: 'g', testField: 'null' },
];

export const supportedFilters = () => [
export const supportedFilters = adapterName => [
'equality',
'equality_case_insensitive',
adapterName !== 'prisma_sqlite' && 'equality_case_insensitive',
'in_value',
'string',
'string_case_insensitive',
adapterName !== 'prisma_sqlite' && 'string',
adapterName !== 'prisma_sqlite' && 'string_case_insensitive',
];
22 changes: 16 additions & 6 deletions packages/fields/src/types/Text/Implementation.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,16 @@ export class Text extends Implementation {
return { [`${this.path}`]: item => item[this.path] };
}
gqlQueryInputFields() {
const { listAdapter } = this.adapter;
return [
...this.equalityInputFields('String'),
...this.stringInputFields('String'),
...this.equalityInputFieldsInsensitive('String'),
...this.stringInputFieldsInsensitive('String'),
...(listAdapter.name === 'prisma' && listAdapter.provider === 'sqlite'
? []
: [
...this.stringInputFields('String'),
...this.equalityInputFieldsInsensitive('String'),
...this.stringInputFieldsInsensitive('String'),
]),
...this.inInputFields('String'),
];
}
Expand All @@ -44,11 +49,16 @@ export class Text extends Implementation {
const CommonTextInterface = superclass =>
class extends superclass {
getQueryConditions(dbPath) {
const { listAdapter } = this;
return {
...this.equalityConditions(dbPath),
...this.stringConditions(dbPath),
...this.equalityConditionsInsensitive(dbPath),
...this.stringConditionsInsensitive(dbPath),
...(listAdapter.name === 'prisma' && listAdapter.provider === 'sqlite'
? {}
: {
...this.stringConditions(dbPath),
...this.equalityConditionsInsensitive(dbPath),
...this.stringConditionsInsensitive(dbPath),
}),
// These have no case-insensitive counter parts
...this.inConditions(dbPath),
};
Expand Down
8 changes: 4 additions & 4 deletions packages/fields/src/types/Text/test-fixtures.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,12 @@ export const storedValues = () => [
{ name: 'g', testField: null },
];

export const supportedFilters = () => [
export const supportedFilters = adapterName => [
'null_equality',
'equality',
'equality_case_insensitive',
adapterName !== 'prisma_sqlite' && 'equality_case_insensitive',
'in_empty_null',
'in_value',
'string',
'string_case_insensitive',
adapterName !== 'prisma_sqlite' && 'string',
adapterName !== 'prisma_sqlite' && 'string_case_insensitive',
];
8 changes: 4 additions & 4 deletions packages/fields/src/types/Url/test-fixtures.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,12 @@ export const storedValues = () => [
{ name: 'g', testField: null },
];

export const supportedFilters = () => [
export const supportedFilters = adapterName => [
'null_equality',
'equality',
'equality_case_insensitive',
adapterName !== 'prisma_sqlite' && 'equality_case_insensitive',
'in_empty_null',
'in_value',
'string',
'string_case_insensitive',
adapterName !== 'prisma_sqlite' && 'string',
adapterName !== 'prisma_sqlite' && 'string_case_insensitive',
];
Loading

0 comments on commit 0de2d55

Please sign in to comment.