| 1 | // CodeQuery is a library that allows you to write SQL queries in a type-safe way using TypeScript. |
| 2 | // It's designed to be as close as SQL as possible, but with the benefits of TypeScript. |
| 3 | // Typescript is actually a very good fit because of it's mapping capabilities. |
| 4 | |
| 5 | // first we create two tables users and logins |
| 6 | const users = createTable(sqliteProvider, "user", table => ({ |
| 7 | id: table.number(c => c.pk(true)), |
| 8 | name: table.string(), |
| 9 | })); |
| 10 | |
| 11 | const logins = createTable(sqliteProvider, "login", table => ({ |
| 12 | id: table.number(c => c.pk(true)), |
| 13 | userId: table.number(c => c.fk(users.columns.id)), |
| 14 | loginTime: table.number(), |
| 15 | success: table.bool() |
| 16 | })); |
| 17 | |
| 18 | // create a query that will return the amount of successful and failed logins per user |
| 19 | const counts = users.from() |
| 20 | .innerJoin(logins, ({user, login}) => user.id.eq(login.userId)) |
| 21 | .groupBy(r => r.user.id) |
| 22 | .select(r => ({ |
| 23 | userId: r.key, |
| 24 | success: r.sum(l => l.login.success.when(true,1, 0)), |
| 25 | fail: r.sum(l => l.login.success.when(false,1, 0)) |
| 26 | }), 'counts'); |
| 27 | |
| 28 | const query = await users.from() |
| 29 | .innerJoin(counts, ({user, counts}) => user.id.eq(counts.userId)) |
| 30 | .select(r => ({ |
| 31 | userId: r.user.id, |
| 32 | name: r.user.name, |
| 33 | success: r.counts.success, |
| 34 | fail: r.counts.fail |
| 35 | })) |
| 36 | .fetchAll(); |
| 37 | |
| 38 | /* this will produce the following SQL: |
| 39 | SELECT |
| 40 | user.id, |
| 41 | user.name, |
| 42 | counts.success, |
| 43 | counts.fail |
| 44 | FROM user |
| 45 | INNER JOIN ( |
| 46 | SELECT |
| 47 | user.id, |
| 48 | SUM(CASE WHEN login.success THEN 1 ELSE 0 END) as success, |
| 49 | SUM(CASE WHEN NOT login.success THEN 1 ELSE 0 END) as fail |
| 50 | FROM user |
| 51 | INNER JOIN login ON user.id = login.userId |
| 52 | GROUP BY user.id |
| 53 | ) as counts ON user.id = counts.userId |
| 54 | */ |
| 55 |
| 1 | // When you use JSON.parse, TypeScript assumes the output to be of the type you specify, but it's not enforced on runtime. |
| 2 | // This could lead to potential runtime errors that are hard to catch |
| 3 | // Inspired by Elm decoders with a simple API |
| 4 | |
| 5 | // a sample usage: |
| 6 | |
| 7 | interface Dog { |
| 8 | name: string; |
| 9 | nickNames: string[]; |
| 10 | size: 'small' | 'medium' | 'large'; |
| 11 | // other properties including the breed |
| 12 | properties: Record<string, string> & { breed: string; } |
| 13 | birthDate?: Date; |
| 14 | } |
| 15 | |
| 16 | // custom decoder for properties type |
| 17 | const propertiesDecoder: Decoder<Dog["properties"]> = { |
| 18 | decode(obj: any): DecoderResult<Dog["properties"]> { |
| 19 | // only if obj is an object and not null |
| 20 | if (obj && typeof obj == "object") { |
| 21 | // fill breed |
| 22 | const props: Dog["properties"] = {breed: ''}; |
| 23 | // then the rest |
| 24 | Object.keys(obj).forEach(k => { |
| 25 | if (typeof obj[k] === 'string') |
| 26 | props[k] = obj[k]; |
| 27 | }); |
| 28 | return resolve(props); |
| 29 | } |
| 30 | return fallback(); |
| 31 | }, fallback(): Dog["properties"] { |
| 32 | return {breed: ''}; |
| 33 | } |
| 34 | } |
| 35 | |
| 36 | |
| 37 | const dogDecoder = decodeObject<Dog>({ |
| 38 | name: decodeString, |
| 39 | nickNames: decodeArray(decodeString), |
| 40 | size: decodeUnionLiterals('small', 'medium', 'large'), |
| 41 | birthDate: decodeOptional(decodeDate), |
| 42 | properties: propertiesDecoder |
| 43 | }) |
| 44 | |
| 45 | const jsonString = '...'; |
| 46 | const dog: Dog = decode.parse(dogDecoder, jsonString); |
| 47 | // dog is now always safe to use |
| 48 |
| 1 | Since primary school, I've been writing programs and messing around with code. |
| 2 | Not only by what it does, but by the way it's structured and presented. |
| 3 | I call it abstract art in it's finest form. I even wrote my wife a love letter in code. |
| 4 | My big motto: know what you are doing. Spent time to things you don't understand - it's always pays off on the long run. |
| 5 | |
| 6 | Feel free to browse and look through my projects. |
| 1 | <!--This tiny utility will enable you to use Vue in a declarative way in your static markup with some added benefits. No code needed to create and mount a Vue instance - it's all part of your markup. This utility is really small (<100 lines, 1Kb) and doesn't do anything on its own. It's only brings the power of Vue in a another way. --> |
| 2 | <!--Vue is already bundles in this package. Note you only need to include the packge. Nothing more.--> |
| 3 | |
| 4 | <a href="https://github.com/itechodev/vue-hydrate">Github repo</a> |
| 5 | |
| 6 | <script src="https://unpkg.com/vue-hydrate@1.0/dist/vue-hydrate-bundle.js"></script> |
| 7 | |
| 8 | <!--You can use any of Vue's rich feature sets. Start learning from https://vuejs.org/v2/guide/#Declarative-Rendering. --> |
| 9 | <!--Vue-hydate adds the following 4 features:--> |
| 10 | |
| 11 | <div v-data="{message: 'Hydration works', count: 1}" ref="first"> |
| 12 | <div @click="count++">{{ message }} with count: {{ count }}</div> |
| 13 | </div> |
| 14 | |
| 15 | <div v-data="data"> |
| 16 | <div @click="inc">{{ message }} with count: {{ count }}</div> |
| 17 | </div> |
| 18 | |
| 19 | <script> |
| 20 | |
| 21 | var data = { |
| 22 | count: 1, |
| 23 | mounted() { |
| 24 | console.log('Instance mounted'); |
| 25 | }, |
| 26 | message: 'Increase both', |
| 27 | inc() { |
| 28 | this.count++; |
| 29 | this.$instances.first.count++; |
| 30 | } |
| 31 | } |
| 32 | </script> |
| 33 |